Description
The Analytics Query Builder's result grid renders every cell as a raw string — numeric and
timestamp alike: getResultColumns in
apps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/result.ts sets
valueFormatter: (params) => renderCell(params.value), and renderCell is String(value) with no
numeric or datetime handling. A row-mode or aggregate query that returns a large integer, a sub-unit
decimal, or an epoch-millis timestamp (e.g. request_time) shows every digit unrounded and every
timestamp as a raw number — unlike the rest of the app, which already has the right building blocks
for this: apps/ai-dial-admin/src/constants/grid-columns/grid-columns.tsx:1480-1495 formats a
numeric column with formatNumberWithExponent, apps/ai-dial-admin/src/constants/grid-columns/configs.ts
already has a dateTimeColumn partial ColDef for datetime columns, and the Analytics conversations
log already specifies (and implements) numeric-formatting discipline for its Tokens and Cost columns
via formatCompactNumber / formatSignificantCost
(apps/ai-dial-admin/src/utils/analytics/conversation-formatting.ts).
A single numeric formatter for every value was measured against a real usage-log distribution and
rejected: a compact/exponent formatter renders a typical sub-unit decimal as effectively zero, and a
thousand-delimited formatter does the same at two decimal places — both destroy the signal a money-like
decimal carries, while compaction is the only readable choice for a very large integer sum. The fix
branches by the result column's resolved value class:
Integer / Long — compact K/M/B/T notation (formatNumberWithExponent).
Decimal — significant-digit formatting so a sub-unit value survives (a currency-agnostic
variant of formatSignificantCost's digit logic — that formatter itself always prefixes $ and
cannot be reused as-is for a non-money decimal).
Timestamp / Date — reuse the existing dateTimeColumn ColDef rather than a hand-rolled
call.
- Everything else (a
Uuid/Enum/Boolean dimension, or a computed column with no resolvable
value class) stays unchanged.
The value class comes from two existing sources: the declared schema type resolved via
buildColumnLabels (executed-meta.ts) for a row-mode/dimension column naming a real schema field,
and — for an aggregate output column under an alias — ExecutedQueryMeta.aggregateColumns (already
built from group_by semantics) plus the returned values' own shape (whole vs. fractional), scoped
to exclude the untranslated-SQL fallback so a SQL view's raw id/epoch columns are never
misclassified as a measure. Keep the exact value reachable via the cell's tooltip, matching the
precedent column.
Related issues
No response
Details
apps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/result.ts — getResultColumns,
renderCell (the gap: no numeric or datetime branch at all)
apps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/executed-meta.ts —
buildColumnLabels already resolves a returned column to its AnalyticsEntityField for a display
name; extending it to also carry the field's declared type is the natural place to source the
type; ExecutedQueryMeta.aggregateColumns already marks a computed/aggregate output column
apps/ai-dial-admin/src/components/Analytics/QueryBuilder/Result/chart-options.ts —
getStrictNumericColumns already confirms an aggregate column is numeric throughout
apps/ai-dial-admin/src/models/analytics/query.ts — StructuredQueryResult.columns is untyped
(string[]), confirming a returned column carries no type of its own
apps/ai-dial-admin/src/constants/grid-columns/configs.ts — dateTimeColumn, numericColumn
(align-right/comparator risk flagged, not resolved, in the proposal)
apps/ai-dial-admin/src/constants/grid-columns/grid-columns.tsx:1480-1495 — the precedent column
(parameters) applying formatNumberWithExponent in valueFormatter, tooltipValueGetter and
filterValueGetter
apps/ai-dial-admin/src/utils/formatting/number-formatting.ts,
apps/ai-dial-admin/src/utils/formatting/date.ts and
apps/ai-dial-admin/src/utils/analytics/conversation-formatting.ts — the formatters to reuse (one
new currency-agnostic significant-digit formatter is needed for the Decimal branch)
- Scope:
apps/ai-dial-admin/src/components/Analytics/** and the formatting/grid-column utilities
above only; no backend or API contract change. Full analysis in the OpenSpec change
analytics-numeric-column-rounding (proposal + BA gap review)
Confidential information
Description
The Analytics Query Builder's result grid renders every cell as a raw string — numeric and
timestamp alike:
getResultColumnsinapps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/result.tssetsvalueFormatter: (params) => renderCell(params.value), andrenderCellisString(value)with nonumeric or datetime handling. A row-mode or aggregate query that returns a large integer, a sub-unit
decimal, or an epoch-millis timestamp (e.g.
request_time) shows every digit unrounded and everytimestamp as a raw number — unlike the rest of the app, which already has the right building blocks
for this:
apps/ai-dial-admin/src/constants/grid-columns/grid-columns.tsx:1480-1495formats anumeric column with
formatNumberWithExponent,apps/ai-dial-admin/src/constants/grid-columns/configs.tsalready has a
dateTimeColumnpartialColDeffor datetime columns, and the Analytics conversationslog already specifies (and implements) numeric-formatting discipline for its Tokens and Cost columns
via
formatCompactNumber/formatSignificantCost(
apps/ai-dial-admin/src/utils/analytics/conversation-formatting.ts).A single numeric formatter for every value was measured against a real usage-log distribution and
rejected: a compact/exponent formatter renders a typical sub-unit decimal as effectively zero, and a
thousand-delimited formatter does the same at two decimal places — both destroy the signal a money-like
decimal carries, while compaction is the only readable choice for a very large integer sum. The fix
branches by the result column's resolved value class:
Integer/Long— compactK/M/B/Tnotation (formatNumberWithExponent).Decimal— significant-digit formatting so a sub-unit value survives (a currency-agnosticvariant of
formatSignificantCost's digit logic — that formatter itself always prefixes$andcannot be reused as-is for a non-money decimal).
Timestamp/Date— reuse the existingdateTimeColumnColDefrather than a hand-rolledcall.
Uuid/Enum/Booleandimension, or a computed column with no resolvablevalue class) stays unchanged.
The value class comes from two existing sources: the declared schema type resolved via
buildColumnLabels(executed-meta.ts) for a row-mode/dimension column naming a real schema field,and — for an aggregate output column under an alias —
ExecutedQueryMeta.aggregateColumns(alreadybuilt from
group_bysemantics) plus the returned values' own shape (whole vs. fractional), scopedto exclude the untranslated-SQL fallback so a SQL view's raw id/epoch columns are never
misclassified as a measure. Keep the exact value reachable via the cell's tooltip, matching the
precedent column.
Related issues
No response
Details
apps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/result.ts—getResultColumns,renderCell(the gap: no numeric or datetime branch at all)apps/ai-dial-admin/src/components/Analytics/QueryBuilder/utils/executed-meta.ts—buildColumnLabelsalready resolves a returned column to itsAnalyticsEntityFieldfor a displayname; extending it to also carry the field's declared
typeis the natural place to source thetype;
ExecutedQueryMeta.aggregateColumnsalready marks a computed/aggregate output columnapps/ai-dial-admin/src/components/Analytics/QueryBuilder/Result/chart-options.ts—getStrictNumericColumnsalready confirms an aggregate column is numeric throughoutapps/ai-dial-admin/src/models/analytics/query.ts—StructuredQueryResult.columnsis untyped(
string[]), confirming a returned column carries no type of its ownapps/ai-dial-admin/src/constants/grid-columns/configs.ts—dateTimeColumn,numericColumn(align-right/comparator risk flagged, not resolved, in the proposal)
apps/ai-dial-admin/src/constants/grid-columns/grid-columns.tsx:1480-1495— the precedent column(
parameters) applyingformatNumberWithExponentinvalueFormatter,tooltipValueGetterandfilterValueGetterapps/ai-dial-admin/src/utils/formatting/number-formatting.ts,apps/ai-dial-admin/src/utils/formatting/date.tsandapps/ai-dial-admin/src/utils/analytics/conversation-formatting.ts— the formatters to reuse (onenew currency-agnostic significant-digit formatter is needed for the
Decimalbranch)apps/ai-dial-admin/src/components/Analytics/**and the formatting/grid-column utilitiesabove only; no backend or API contract change. Full analysis in the OpenSpec change
analytics-numeric-column-rounding(proposal + BA gap review)Confidential information