Skip to content

feat(cli): dashboard widget reference integrity check (dataset → dimensions/measures + chartConfig fields)#1722

Merged
os-zhuang merged 1 commit into
mainfrom
feat-1721-widget-reference-integrity
Jun 11, 2026
Merged

feat(cli): dashboard widget reference integrity check (dataset → dimensions/measures + chartConfig fields)#1722
os-zhuang merged 1 commit into
mainfrom
feat-1721-widget-reference-integrity

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #1721.

What

Extends the #1719 semantic widget-binding pass (validateWidgetBindings) into the full dashboard widget reference integrity check the issue proposes, and surfaces it in all four build-time tools:

Rule Severity Issue item
widget-dataset-unknown error (a) dataset resolves to a declared Dataset
widget-dimension-unknown error (b) every dimensions[] entry is a real dataset dimension
widget-measure-unknown error (c) every values[] entry is a real dataset measure
chart-field-unknown error (d) chartConfig.xAxis.field resolves to a dataset dimension; yAxis[].field / series[].name resolve to a measure selected in values
chart-config-missing warning (d) chart-type widget with no chartConfig at all
table-count-only warning (e) — already landed in #1719, unchanged
  • validate — semantic pass after safeParse succeeds; errors fail with located, corrective messages (and in --json); warnings print non-blocking (--strict makes them fatal).
  • build/compile — same: errors fail the build where the cutover damage actually occurred (CI).
  • lint — findings pass their real severity through (was hardcoded warning).
  • doctor — new "Dashboard integrity — All widgets resolve datasets, dimensions, and measures" section mirroring the orphan-view pass.

Messages list the declared names and carry a did-you-mean suggestion with containment checked before edit distance, so the cutover's canonical drift (amountsum_amount) is suggested:

✗ Dashboard widget integrity failed (1 issue)
• dashboard "pipeline_dashboard" › widget "pipeline_trend_90d": chartConfig.yAxis[0].field "amount"
  does not resolve to a measure of dataset "opportunity_metrics" (declared measures: opp_count,
  total_amount, avg_amount).
    Post-cutover data is keyed by the dataset's measure NAME, not the base column.
    rule: chart-field-unknown  at dashboards[0].widgets[3]

Design notes

  • Errors are not suppressible — they describe a binding the analytics service cannot satisfy; suppressWarnings: ['<rule-id>'] keeps working for the two advisory rules.
  • A chartConfig field that names an already-invalid values/dimensions entry is not double-reported — rules (b)/(c) own that error.
  • A widget whose dataset doesn't resolve reports once and skips the name checks (nothing to resolve against).
  • Per the issue, the check lives in the CLI (where multi-package config is assembled), not the spec schema — a widget in one package can resolve a dataset in another.
  • A measure that is declared on the dataset but not selected in the widget's values gets a targeted message ("the query result will not contain it") instead of the generic one.

Example apps

chart-config-missing flagged 19 chart widgets across the three example apps — all authored without chartConfig. They now carry the explicit mapping (xAxis.field = dimension, yAxis[].field = measure name), the authoring shape templates#30 standardized on after browser-verifying it fixes the blank charts. Note the tension: objectui HEAD's DatasetWidget (since 92449ef99) derives series from values and ignores chartConfig, so at HEAD the warning is advisory rather than a real breakage — but published renderers consume it, and the explicit form is compatible both ways. If values-derived rendering becomes the contract everywhere, chart-config-missing can be dropped without touching the error rules.

app-todo's two count-only record-listing tables (overdue_tasks_table, due_today) still warn under table-count-only — re-modeling them as object-bound ListViews (ADR-0017) is #1719's failure class, left as a follow-up.

Verification

🤖 Generated with Claude Code

…/measures + chartConfig)

Closes #1721. The ADR-0021 single-form cutover makes every DashboardWidget
select its dataset's dimensions/measures BY NAME, but nothing validated
those references — a widget could name a dataset that doesn't exist, a
measure the dataset never declares, or point chartConfig.yAxis[].field at
a stale base column, and validate/lint/doctor/build all stayed green while
the page rendered an empty series. Downstream this broke 36 widgets across
11 template dashboards (templates#27, templates#30) with a green build.

`validateWidgetBindings()` (the #1719 semantic pass) now returns
severity-carrying findings:

errors — the binding cannot be satisfied; validate and build FAIL:
- widget-dataset-unknown    `dataset` resolves to no declared Dataset
- widget-dimension-unknown  a `dimensions[]` entry isn't a dataset dimension
- widget-measure-unknown    a `values[]` entry isn't a dataset measure
- chart-field-unknown       chartConfig xAxis.field doesn't resolve to a
  dataset dimension, or yAxis[].field / series[].name doesn't resolve to a
  measure selected in `values` (post-cutover rows are keyed by measure
  NAME, e.g. sum_amount — not the base column amount)

warnings — advisory, suppressible per widget via suppressWarnings:
- chart-config-missing      chart-type widget with no chartConfig (renders
  an empty series on chartConfig-driven renderers; templates#30 verified
  in-browser that adding the mapping fixes it)
- table-count-only          unchanged from #1719

Errors are not suppressible, and messages carry the declared-name list
plus a did-you-mean suggestion (containment-first, so amount → sum_amount).
Surfaces: validate + compile fail on errors (human + --json), lint passes
severity through, doctor gains a "Dashboard integrity" section mirroring
the orphan-view pass. A chartConfig field naming an already-invalid
selection entry is not double-reported — rules (b)/(c) own that error.

The example apps' chart widgets now carry explicit chartConfig (the
authoring shape templates#30 standardized on; objectui HEAD derives series
from `values` and ignores it, so this is compatible both ways). app-todo's
two count-only record-listing tables still warn — that re-modeling to
ListViews (ADR-0017) is #1719 territory, left as a follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 11, 2026 10:28am

Request Review

@os-zhuang
os-zhuang merged commit aebc256 into main Jun 11, 2026
12 checks passed
@os-zhuang
os-zhuang deleted the feat-1721-widget-reference-integrity branch June 11, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

validate/doctor: add Dashboard widget reference integrity check (dataset → dimensions/measures + chartConfig fields)

1 participant