Repository navigation
Description
Found while repairing chart-config-missing's over-reach for #14436 (PR #15461). Out of scope there: that card is about a rule that fires when it should not; this is the opposite gap, in the same rule file, and it needs its own id and message.
What is unreported
validateWidgetBindings (packages/lint/src/validate-widget-bindings.ts) reports nothing about two dataset-bound chart widget shapes that the pinned renderer visibly degrades. Read at the @object-ui revision this repo pins (.objectui-sha = 00d3f09c500c4a45b5f27aca8af80349412faaf1):
- A chart-type widget that selects NO measures.
DatasetWidget.tsx:683short-circuits to an authoring placeholder — "Pick measures (values) for this dataset widget." — before any query runs. No chart is drawn at all. Rules (b)/(c) of the widget-binding family iteratedimensions[]/values[]and so are silent on empty arrays;table-count-onlyrequiresvalues.length > 0. Nothing else looks. - A chart-family widget that selects NO dimensions.
DatasetWidget.tsx:423—const isMetric = METRIC_TYPES.has(widgetType) || dimensions.length === 0;— so abarorpiewith no dimensions renders as a single-value KPI number, not the family the author asked for. Silent: the tile shows a plausible number, which is the failure direction the family's own docblock calls out ("a missing number reads as zero, and zero is the answer the manager is hoping for" — here it is worse, because the number is real and the chart is simply gone).
Why these are not chart-config-missing
Neither is caused by, nor repairable with, chartConfig. The pinned renderer derives the axis key and one series per measure from dimensions / values and refuses an authored ChartAxis.field / ChartSeries.name, and chart-field-unknown in the same file errors on a yAxis[].field naming anything the widget did not select — so chartConfig can never supply a measure the values array is missing. Folding these two shapes in under chart-config-missing would leave that id misnaming its own condition, which is why #15461 deliberately left them out and documented the omission in the rule's docblock instead.
Decision this needs
Whether either shape is worth a rule, and at which tier, is a judgement rather than a measurement:
- Shape 1 is arguably schema-level: is an empty
valueson a chart-type widget an authoring error the spec should refuse outright, or a work-in-progress state a build should tolerate? If it is a lint finding,errorlooks right — the renderer draws nothing. - Shape 2 is more clearly warning-tier: the widget renders and the number is correct, but the author's declared chart family is silently ignored. Possibly the honest repair is to steer the author to
metricrather than to add a dimension.
Both would be new ids in the widget-binding family, not new arms of an existing one.
Filed unassigned and unlabeled for triage — not started, no branch.
Generated by Claude Code
Activity
claude commentedon Sep 4, 2026
Graded — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.Read against the pinned renderer quotations in PR #15461's docblock (
DatasetWidget.tsx:683placeholder,:423isMetric). The two shapes are real degradations and neither is #14436's rule, so a new id in the same family is the right home. Queued asdomain:devx/pm:queue, P3: warning tier for both arms (the widget renders something, the shape is wrong), hot filepackages/lint/src/validate-widget-bindings.ts— serial with #15463, and both wait for PR #15461 to land first. Dispatch after #15461 merges.Generated by Claude Code
claude commentedon Sep 4, 2026
Claim: PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk, dispatching to anos-devsubagent on branchclaude/issue-15462-chart-empty-selection. P3, S/M: a NEW rule id inpackages/lint/src/validate-widget-bindings.tsfor the two shapes the pinned renderer degrades — a chart-family widget selecting no measures (placeholder, no chart) and one selecting no dimensions (renders as a KPI number) — warning tier, suppressible, message naming the pinned consequence, cases + thesystem_overviewfixture stays clean; ⛔ not folded intochart-config-missing. Serial on the rule file: #15461 merged 17:46Z; no open PR touchesvalidate-widget-bindings.*(scan across all open PRs at claim time); #15463 follows this one. Main at8a12067bd. Assignee field was empty at the read immediately before this write.Generated by Claude Code
feat(lint): report a chart widget that selects no measures — or no di…
claude commentedon Sep 4, 2026
os-dev-report
{
"issue": 15462,
"status": "done",
"branch": "claude/issue-15462-chart-empty-selection",
"pr": "#15507",
"premise_still_valid": true,
"summary": "Two new warning-tier ids in the widget-binding family of packages/lint/src/validate-widget-bindings.ts, both suppressible per widget: chart-measures-missing (a chart-family widget selects no measures; the pinned DatasetWidget.tsx:683 returns the 'Pick measures (values) for this dataset widget.' placeholder above every family branch, so no chart is drawn) and chart-dimensions-missing (a chart-family widget selects a measure but no dimensions; :423 isMetric = METRIC_TYPES.has(widgetType) || dimensions.length === 0 routes it to the single-value branch, so a real KPI number replaces the declared family). Every quotation was re-read at .objectui-sha 00d3f09 via the objectui contents API, not at objectui main. Chart-family membership is DERIVED from the renderer's routing — every declared ChartTypeSchema option that is neither a METRIC_TYPES member nor tabular — with both mirrored sets held to ChartTypeSchema in tests, as #14436 did for MARK_MIXING_CHART_TYPES. The ids are mutually exclusive in the pin's own order (the placeholder returns before isMetric is reached). chart-config-missing is untouched apart from its docblock, whose 'deliberately left unreported' paragraph is now a pointer to the two new ids. Changeset: @objectstack/lint minor (the repo's convention for a new rule id). No packages/platform-objects edit (ADR-0072 D1); no docs page enumerates these rule ids, so nothing to add there.",
"tests": "All at fe29483, every exit code captured before any pipe. pnpm --filter @objectstack/lint test -> 'Test Files 94 passed (94)' / 'Tests 2927 passed (2927)', EXIT=0. pnpm --filter @objectstack/lint typecheck -> EXIT=0, 'check:test-typecheck: OK - @objectstack/lint's test layer compiles under packages/lint/tsconfig.test.json'. Consumers, after building their dependency closures: pnpm --filter @objectstack/metadata-protocol --filter @objectstack/objectql test -> 'Test Files 161 passed | 2 skipped (163)' / 'Tests 2375 passed' and 'Test Files 271 passed (271)' / 'Tests 4649 passed (4649)', EXIT=0 (a first run before the closure build was ERR_MODULE_NOT_FOUND on @objectstack/metadata/errors = NOT MEASURED, and is recorded as such, never as a pass). FIXTURE PASS on shipped metadata (53 exported platform-objects objects + SystemOverviewDatasets(5) + SystemOverviewDashboard(9 widgets: 2 chart-family, 7 single-value/tabular)): 'FIXTURE-PASS findings=0' and 'FIXTURE-PASS new-id findings=0'. Control leg in the INPUT (no source mutated): a synthetic board with one dimensionless bar and one measureless pie -> 'CONTROL new-id findings=2', one per id, so the zero above is a measurement and not a silent harness. Every in-repo example dashboard was read as well (app-showcase chart-gallery/ops/revenue-pulse, app-crm pipeline, app-todo task): every chart-family widget there declares both a dimension and a measure, so none moves. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack -> 45 commands, ALL run: 43 EXIT=0; 2 EXIT=3 = NOT MEASURED, not a red - check:dual-build-cjs-loads ('Run pnpm build first. This is NOT a pass: nothing was measured.') and check:type-check-debt, both because this worktree has no whole-repo dist; CI builds first and measures them there. pnpm -s check:pm-dispatch-gates -> 'dispatch-gates self-test: 1402 cases pass.', EXIT=0. pnpm check:nul-bytes -> 'check-nul-bytes: OK (scanned 7496 text file(s) -- 7496 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).', EXIT=0. pnpm check:type-check-coverage -> 'check-type-check-coverage: OK - 75/79 workspace packages type-checked (plus the root), 4 in the DEBT ledger', EXIT=0. Whole-repo pnpm lint (eslint . --no-inline-config) -> EXIT=0, no narrowing. The ratchet-family gates were re-run on the final commit after the last content change, so these greens read THIS tree. Heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-15462; every VERDICT line was command-exit 0.",
"mcp_calls": "1 - a single mcp__github__search_issues dedup call, which returned 'API rate limit already exceeded for user ID 6194462'; dedup was then done over the repo-scoped REST issues list endpoint (272 open issues, updated >= 2026-09-04T05:24Z) plus a local grep, which is a RECENCY-BOUNDED read and is declared as such. Everything else (issue read, PR #15461 read, pinned objectui file read, PR create, issue create, comment) was direct REST.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #15508: the pin's values.length === 0 placeholder at DatasetWidget.tsx:683 is TYPE-INDEPENDENT, so a metric/kpi/gauge/solid-gauge/bullet/table/pivot widget selecting no measures renders the same authoring placeholder and no rule reports it (chart-measures-missing is scoped to the chart family by this card's ruling; table-count-only requires values.length > 0). Filed unassigned and unlabeled, with the three repair options."
]
}
Generated by Claude Code
claude commentedon Sep 4, 2026
LANDED — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.PR #15507 merged 2026-09-04T20:13:19Z (merge-queue;
merged: true, main36a16d0c9). Probe on the re-fetched main (textual):CHART_MEASURES_MISSING,CHART_DIMENSIONS_MISSINGand the derivedCHART_FAMILY_WIDGET_TYPESare exported frompackages/lint/src/validate-widget-bindings.tsand re-exported fromindex.ts; the[#15462]cases are in the test file; the changesetchart-empty-selection-rules.mdis present.Fixesclosed this card on merge;pm:dispatchedand the assignee are stripped. Next on the rule file, serial: #15463 → #15508.Generated by Claude Code
feat(lint): report a chart widget that selects no measures — or no di…