feat(cli): build-time warning for count-only table/pivot dashboard widgets (table-count-only)#1720
Merged
Merged
Conversation
…mensions Closes #1719. After the ADR-0021 single-form cutover, a `table`/`pivot` DashboardWidget whose selected `values` resolve to only `count` measures and which declares no `dimensions` requests a one-row summary from the analytics service — the shape a `metric` widget wants, but for a table it almost always means the author wanted a per-record listing (which is not an analytics dataset at all; ADR-0017 ListView territory). The build was silently green on this shape; downstream it collapsed 19 record-listing tables across 11 dashboards (objectstack-ai/templates#27). `objectstack build` now emits a non-fatal `table-count-only` warning per offending widget, keyed on the WIDGET's binding (not the dataset): the check runs after dataset references are resolved, so a dataset that also carries sum measures/dimensions the widget doesn't select still warns. Dangling dataset refs and unresolvable measure names are left to their own diagnostics; derived and count_distinct measures don't count as plain counts. - new `validateWidgetBindings()` in the CLI build pipeline (mirrors the ADR-0032 `validateStackExpressions` semantic-phase pattern); warnings print in human output and land in `--json` as `warnings[]` - same rule surfaces through `objectstack lint` - deliberate single-row tables opt out per widget via the new schema field `suppressWarnings: ['table-count-only']` — a metadata-level escape hatch, since source comments do not survive config bundling Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1719.
What
After the ADR-0021 single-form cutover, a
table/pivotDashboardWidgetwhose selectedvaluesresolve to onlycountmeasures and which declares nodimensionsasks the analytics service for a single summary row. That's exactly what ametricwidget wants — but for a table it almost always means the author wanted a per-record listing, which is not an analytics dataset at all (ADR-0017 ListView territory).objectstack buildwas silently green on this shape; downstream it collapsed 19 record-listing tables across 11 dashboards (templates#27).objectstack buildnow emits a non-fataltable-count-onlywarning per offending widget:How
packages/cli/src/utils/validate-widget-bindings.ts— new semantic-phase check mirroring the ADR-0032validateStackExpressionspattern. It runs after Zod parse, when each widget'sdatasetname is linked to itsdefineDatasetand everyvaluesentry resolves to a measure with a knownaggregate. Per the issue, the heuristic is keyed on the widget's binding, not the dataset — the repro dataset also carries asummeasure and a dimension, and still warns because the widget selects neither.compile.ts(=build) — prints warnings in human output;--jsongains awarnings[]array. The build never fails on these.lint.ts— the same rule surfaces throughobjectstack lintwith rule idtable-count-only, consistent with the existing rule registry.spec/ui/dashboard.zod.ts— new optional widget fieldsuppressWarnings: string[]as the opt-out for deliberate single-row tables.Deviations from the issue
The proposed
// objectstack-disable-next-line table-count-onlycomment can't work here: the config is evaluated through bundle-require, so source comments never reach the metadata the check runs on. The suppression is metadata-level instead (suppressWarnings: ['table-count-only']on the widget), schema-validated and mentioned verbatim in the warning text.Deliberately not warned (each is a different diagnostic or a legitimate shape): dangling dataset references, unresolvable measure names, mixed count+non-count selections,
count_distinct, derived measures, any widget with ≥1 dimension, andmetricwidgets.Testing
validate-widget-bindings.test.ts)@objectstack/clisuite: 28 files / 240 tests green;@objectstack/specdashboard+stack tests green; both packages compileobjectstack buildon the issue's minimal repro — warning fires, build stays green,--jsoncarries the warning,suppressWarningssilences it;objectstack lintreports the same rulesystem_overviewtable widget declaresdimensions: ['action']and does not trip the rule🤖 Generated with Claude Code