Skip to content

fix(views): chart gradient ids survive any caller text; dashboard tables read cleanly - #2333

Merged
Makisuo merged 3 commits into
mainfrom
fix/charts-kit-correctness
Nov 7, 2026
Merged

Makisuo merged 3 commits into
mainfrom
fix/charts-kit-correctness

Conversation

@Makisuo

@Makisuo Makisuo commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes the charts-kit findings from the usage audit (2026-10-07 to 11-07), each re-checked against origin/main first.

What changed

1. Sparkline crash (prod). TypeError: Invalid Canvas paint: url(#spark-endpoint-GET (unmatched)), 2 hits in 14 days, last at 2026-11-05 06:42Z, and the only canvas paint error in prod. The chart library's canvas painter matches gradients with /^url\(#([^)]+)\)$/, so an id with ) falls through to CSS colour parsing and throws. Its SVG renderer also strips non-[A-Za-z0-9_-] characters, so ids like a.b and a b could collide.

  • Every chart definition now builds gradient ids through a branded GradientId (packages/views/src/charts/definitions/gradient-id.ts). The ids are [A-Za-z0-9_-] only, and anything that had to be rewritten gets a hash suffix so distinct inputs stay distinct.
  • verticalGradient requires a GradientId, so a raw caller string is now a type error.
  • Covered: sparkline, area/line, stacked breakdown, infra metric, fixed metric, anomaly signal, alert rule, analytics traffic, bench overview and the lab spike chart. No call site changed.

2. Dashboard table cells showed raw numbers (0.30000000000000004, 1234567.891). Unitless numeric cells now trim float noise and group values of 10,000 and up. Strings stay exactly as they came: ids, UInt64 counts and versions like 3.10 all arrive as strings.

3. Metric picker showed name::type. Dropped from this PR: #2336 on main fixed the same bug its own way (the input shows the metric name, with the type beside it), so the merge keeps main's version.

Not fixed here

  • Lines drop to 0 after data stops: this is the backend, not the kit. packages/query-engine/src/query-set/series-merge.ts:190 deliberately zero-fills every series in every bucket, for every aggregation. For counts that's correct; for avg, percentiles and gauges it invents zeros. The fix is an aggregation-aware fill in the query engine. Proposed as a follow-up.
  • SQL threshold "0,005 %" next to "Was 0.5": comes from the alert editor (the native number input's locale and web-data/alerts/form-utils.ts threshold conversion). That's the alerts session's (S4) area, so it's left for them.
  • "Charts weirdly cut off" (10-16) and worker page chart padding (10-14): not reproduced. The reports don't name the chart or the data, and the worker detail page has no lab fixture. Needs a session replay or URL to chase.

Verification

  • gradient-id.test.ts: builds real sparkline scenes for worst-case ids (endpoint-GET (unmatched), GET /users/{id}, unicode, NBSP, a b vs a_b), renders the SVG, and checks every url(#…) resolves to a defined gradient and parses with the canvas regex. Mutation check: with the helper returning raw ids, the prod case fails.
  • tiles.test.ts (formatCell).
  • views and web typecheck clean, oxlint -c .oxlintrc.effect.json clean on changed files, packages/views chart tests and the touched web tests pass.
  • Lab: /lab/service-api gains a prod-shaped GET (unmatched) endpoint. Before the fix the dev server logs the exact prod error and the row draws no sparkline; after, it draws.
  • One independent review pass found no gradient bugs. Its formatCell findings (version strings, grouping) are fixed.
Before After
Light before light after light
Dark before dark after dark

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

…e metric picker read cleanly

A raw route like `GET (unmatched)` as a sparkline id crashed the canvas painter
(`Invalid Canvas paint: url(#spark-endpoint-GET (unmatched))`). Every chart
definition now builds gradient ids through a branded `gradientId` helper that
keeps ids to [A-Za-z0-9_-] and hashes anything it had to rewrite.

Dashboard tables format unitless numbers (no float noise, large values grouped)
and the metric picker shows `name (type)` instead of the `name::type` key.
@Makisuo Makisuo added the preview:web Deploy a Workers-only PR preview (no ingest/Electric); see docs/pr-previews.md label Nov 7, 2026
@coderabbitai

coderabbitai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b9dcbbe1-e922-4b08-bd29-a6a7face43b4
Commits

Reviewing files that changed from the base of the PR and between 5a55f5d and 782c502.

Files selected for processing: 16

  • apps/web/src/lab/charts/spike-timeseries.ts
  • apps/web/src/lab/service-api-fixture.ts
  • apps/web/src/page/dashboards/kit/tiles.test.ts
  • apps/web/src/page/dashboards/kit/tiles.ts
  • packages/views/src/charts/definitions/alert-rule.ts
  • packages/views/src/charts/definitions/analytics-traffic.ts
  • packages/views/src/charts/definitions/anomaly-signal.ts
  • packages/views/src/charts/definitions/area.ts
  • packages/views/src/charts/definitions/bench-overview.ts
  • packages/views/src/charts/definitions/fixed-metric-axes.ts
  • packages/views/src/charts/definitions/fixed-metric.ts
  • packages/views/src/charts/definitions/gradient-id.test.ts
  • packages/views/src/charts/definitions/gradient-id.ts
  • packages/views/src/charts/definitions/infra-metric.ts
  • packages/views/src/charts/definitions/sparkline.ts
  • packages/views/src/charts/definitions/stacked-breakdown.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@maple-review-bot

This comment has been minimized.

@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

🍁 Maple PR preview

Note

Preview resources were removed when the preview label came off.

Final commit 6ccee95 · View workflow run

@maple-review-bot

This comment has been minimized.

@Makisuo Makisuo removed the preview:web Deploy a Workers-only PR preview (no ingest/Electric); see docs/pr-previews.md label Nov 7, 2026
@Makisuo

Makisuo commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

Preview deploy was refused by the preview cap (9 open PRs labelled, all parallel audit sessions plus #2326), not by this change. I removed preview:web here to free a slot. The fix is verified locally in /lab/service-api (before/after screenshots above) and by the scene test that renders the prod id; re-add preview:web once a slot is free to test it on a preview.

…x/charts-kit-correctness

# Conflicts:
#	apps/web/src/page/kit/query-builder/metrics-body.ts
@Makisuo Makisuo changed the title fix(views): chart gradient ids survive any caller text; tables and metric picker read cleanly fix(views): chart gradient ids survive any caller text; dashboard tables read cleanly Nov 7, 2026
@Makisuo
Makisuo merged commit 694bc06 into main Nov 7, 2026
23 of 24 checks passed
@Makisuo
Makisuo deleted the fix/charts-kit-correctness branch November 7, 2026 14:12
@maple-review-bot

maple-review-bot Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 10/10 · safe to merge. Contained view-layer change: every gradient and its fill come from one builder, and the new formats are pinned by rendered-scene and string tests.
1 note · tests covered · risk medium

Routes every chart gradient id through a branded sanitizer, so a span name like GET (unmatched) no longer throws in the canvas painter, and formats unitless table cells instead of printing raw floats. Both behaviors are tested; one list-cell path is left unformatted.

  • gradientId keeps only [A-Za-z0-9_-] and appends a hash when it rewrites
  • verticalGradient now takes a branded GradientId
  • formatCell trims and groups unitless numbers via plainNumber
  • Lab gains a GET (unmatched) endpoint and a derived series

Before merge

  • Manual · Re-add preview:web once a slot frees, to see the prod sparkline id render on a preview

Findings

🔵 Note · F1 · Numeric items inside a list cell still print raw float noise

correctness · apps/web/src/page/dashboards/kit/tiles.ts:111

listCellText sends array items through cellText (tiles.ts:299), so a list column holding [0.30000000000000004, 1234567.891] still renders those exactly as they came, while the same value in a scalar cell now reads 0.3 and 1,234,567.89. The list tile is left half-formatted.

Map array items through `formatCell(item, unit)` in `listCellText` (keeping the empty-string case) so list cells format like table cells.
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit 782c502928d56ac7eacf32a1949f07ef018ea26b. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F1 · Note · correctness · apps/web/src/page/dashboards/kit/tiles.ts:111
Numeric items inside a list cell still print raw float noise
`listCellText` sends array items through `cellText` (`tiles.ts:299`), so a list column holding `[0.30000000000000004, 1234567.891]` still renders those exactly as they came, while the same value in a scalar cell now reads `0.3` and `1,234,567.89`. The list tile is left half-formatted.
Suggested fix: Map array items through `formatCell(item, unit)` in `listCellText` (keeping the empty-string case) so list cells format like table cells.

782c502 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

Copy link
Copy Markdown

Merged with 1 step from "Before merge" still open. If it is done, tick it on the review comment; if not, now is the time.

  • Manual · Re-add preview:web once a slot frees, to see the prod sparkline id render on a preview

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