fix(plugin-charts): an object-chart whose specType is a single-value or tabular family draws its routed form, not a silent bar; no default family (objectui#11520) - #11529
Conversation
…ily dispatch; no silent bar default normalizeChartSchema hands the named family to AdvancedChartImpl as named, drawn or not, so a specType of gauge / solid-gauge / metric / kpi / bullet draws the number card and table / pivot the tabular notice, exactly as the same families on chartType do. AdvancedChartImpl's 'bar' default, and its four restatements in the refusal guards, are removed: an absent family is the unknown-type notice. The 105-cell matrix pin (21 families x 5 node shapes, family on specType) holds every cell to its routed form, read off the dispatch's own sets. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…e removed bar default (objectui#11520) Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…spatch, where the family is a drawn one (objectui#11520) AdvancedChartImplProps.chartType is now the family as named (a string), so the literal map could no longer be indexed by it before the dispatch. It is read only by the cartesian tail, which the dispatch guards, so it moves there, typed as a record. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…type instead of a widened record (objectui#11520) Keeps the map's own value types, and adds no explicit any. The emitted declarations are byte-identical. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…amilies, not string (objectui#11520) NormalizedChartSchema['chartType'] (exported) and AdvancedChartImplProps .chartType take DeclaredChartFamily, the union of object-chart's two family keys read off ObjectChartSchema by reference: its chartType union (objectui#11513) and its specType (the spec's ChartType). A misspelled family no longer compiles. The one assertion is the named JSON-boundary cast in normalizeChartSchema; a value outside the type in unvalidated JSON still reaches the dispatch and its unknown-type notice. The changeset's Type paragraph says the member widens to the declared chart families. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Read for this record: card #11520 (body and all six comments; triage ruling 5963338583 governs; claim 5963741843 as amended by REWORK 5964370972; dev reports 5964341782 and 5964488618 and the seat's ACCEPT 5964543734 read as claims to test), PR #11529's body, its 5-file list, the net diff against the merge base (+490 / −46), the source at the head, and the 43 check-runs on the head after every one completed: 40 success, 3 skipped (dependabot, Test (coverage), Test (coverage shard)), 0 failure; the aggregate Test, Bundle Analysis and Spec Main Shape Gate are success. Not governed (5 paths), ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Rendered 2026-10-03T03:02Z from the diff, the card and the head's completed check-runs; nothing built, run or re-run locally. |
Fixes #11520
Clause-②: yes (widening). The faces' accept sets do not move (both accept these documents before and after). One exported type widens:
NormalizedChartSchema['chartType'](@object-ui/plugin-charts) goes from the thirteen drawn families to the declared chart families,DeclaredChartFamily: theobject-chartnode's ownchartTypeunion (objectui#11513) together with itsspecType(the spec'sChartType), both read offObjectChartSchemain@object-ui/typesby reference, never restated. It now carries the family the schema names, drawn or not, and a misspelled family still fails to compile. The claim'snoassumed no exported type would move; this is the flip it provided for.Dispatched by the PM loop, round 1 (
domain:uiseat 1), claim comment5963741843, sessionhttps://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37. Triage ruling5963338583executed as written.The defect, reproduced at BASE
8366accd1An
object-chartwhose family is onspecType(the react tier's key: the react-page wrapper parks theObjectChartblock'stype="gauge"there) withgauge,solid-gauge,metric,kpi,bullet,tableorpivotparses on both faces and draws a bar chart with no note. The new pin's BASE run, through the realSchemaRenderer, read every such cell as one bar mark on one value axis, categories across, no notice. The off-specsunburstonspecTypedrew a bar too.Mechanism, measured as the card read it:
normalizeChartSchemareadspecType, then kept the family only whenRENDERABLEheld it.ChartRenderer'sschema.chartType ?? spec.chartTypewas then unset.AdvancedChartImpldefaulted an unset family to'bar'. Its four refusal guards each restated that default (props.chartType ?? 'bar').The fix
AdvancedChartImpl's family dispatch, keyed onSINGLE_VALUE_CHART_TYPES/TABULAR_CHART_TYPES/RENDERABLEinnormalizeChartSchema.ts. It is the branch thechartTypechannel already reaches, and it draws exactly the forms the ruling names: the number card and the tabular notice.widgetDispatchlives inpackages/plugin-dashboard/src. It routes dashboard widgets to dashboard node types (a metric-card node, a records table, a pivot) and has no tabular notice. plugin-dashboard depends on plugin-charts (as a dev dependency), and plugin-charts could not import it without a reverse dependency. So there is no fork:specTypeis routed through plugin-charts' own dispatch, with no new family list and no edit to either table.normalizeChartSchemahands the named family on as named (chartType, elsespecType, else a baretypethat is a spec family, else a registered keyword's family). It no longer filters byRENDERABLE.specTypenow reaches the dispatch with the same valuechartTypedoes.AdvancedChartImpl: the= 'bar'default is removed. The four guard copies go with it, through oneguardFamilyhelper that readscolumnasbarand nothing as nothing. An absent family is the existing unknown-type notice (data-testid="advanced-chart-unknown-type",role="note", the same element and the "nothing was drawn" string family), reading "This chart names no chart type — nothing was drawn." An off-spec family keeps that notice's existing sentence, which names the value.AdvancedChartImplProps['chartType'](internal, not on the package entry) andeffectiveChartFamily's constraint takeDeclaredChartFamilywith it (patch round 1); no plainstringremains on the family path. The cartesian root map moved below the dispatch, where the family is a drawn one. The emitted declarations of that last step are byte-identical.Callers that relied on the default (Zone 2 item 3). Every source producer that reaches
AdvancedChartImplnames its family explicitly:DatasetPreviewpassesbar/combo;DatasetWidgetpasses its map's family?? 'bar';DashboardRenderer/DashboardGridLayoutpass the series familywidgetDispatchresolved;app-shell,plugin-listandplugin-viewpasschartType || 'bar';chart.chartType ?? 'bar';specType.No caller needed an edit.
ChartRenderer.tsxis unchanged.Pins
packages/plugin-charts/src/__tests__/object-chart-spectype-routing-11520.test.tsx(new), through the realSchemaRendererand this package's registrations:The matrix, 21 families x 5 node shapes = 105 cells, each family on
specType: every family of the installed spec plussunburst. The five shapes:propertiesbag on the object path (the card's document);{ ...props, specType, type });Each cell is held to its routed form, read off the dispatch's sets: the number card, the tabular notice, the family's OWN marks for a drawn family (so a silent bar fails), or the unknown-type notice naming an off-spec value.
The bar control:
bar,columnandhorizontal-bardraw bars in every shape. A barechartnode namingbardraws a bar.Unresolved family: an
object-chartnaming no family (both faces refuse it) and a barechartnaming none show the notice, with zero bar marks.The two channels agree: per family,
specTypedraws the formchartTypedraws (21 rows).Premise: the card's document parses on both faces for all 20 spec families on
specType, andsunburstdoes not.Re-judged:
normalizeChartSchema.test.ts's "leaves a family this renderer cannot draw unset" pinned exactly the removed branch. It is replaced by "hands a family this renderer draws no chart of to the dispatch as named", overmetric,pivot,sunburst, andchartTypewinning overspecType.The objectui#11513
chartTyperefusals stay green:object-chart-declared-families-11513.test.tsx,object-chart-families-11513.test.tsandobject-chart-properties-bag-11276.test.ts.Reverse verification and ablation (predicted first)
All at committed states. The subject resolves to
srcthrough the vitest alias, so nodistleg applies.8366accd1, the final pin)marks:bar.RENDERABLEgate (ablation-replace.mjs, anchor 1 to 0, blob3c1f8ba7todf252daa)sunburstcells, 7 agreement rows, 1 normalizer row= 'bar'alone (anchor 1 to 0, blobb30ae64ato2e1a7193)Each restore was proven by blob equality with
HEADand an emptygit diff HEAD(the tool's own verdict, re-read by hand after each leg).Gates (round 0 at
a1e6721fa; patch round 1 at514d71d1fbelow)pnpm exec vitest run packages/plugin-charts/plus the twopackages/types11513 / 11276 pins: 90 files, 1258 passed, 9 skipped. The skips are the existingdescribe.runIf(DRIVEN)block.git grep -l:object-chart,@object-ui/plugin-charts,ChartRenderer,AdvancedChartImpl, achartnode orchart:bar: 101 files, 3925 passed. They span apps/console, examples/schema-catalog, app-shell, cli, components, core, data-objectstack, plugin-chatbot, plugin-dashboard, plugin-designer, plugin-list, plugin-report, plugin-view, react, runner, sdui-parser, types and scripts.recharts/DatasetWidget/DashboardRenderer/DashboardGridLayoutnot already in the first: 101 files, 1097 passed.pnpm --filter @object-ui/plugin-charts type-check(tsc --noEmitandtsc -p tsconfig.test.json), after its closure was built: exit 0. The rebuiltnormalizeChartSchema.d.tscarriedchartType?: stringata1e6721fa; after patch round 1 it carrieschartType?: DeclaredChartFamily.Bundle Analysisruns it:pnpm turbo run build --filter=./packages/*(39 of 39), thenpnpm --filter @object-ui/console build(tsc, vite build, SDUI manifest,tsconfig.plugin.json): exit 0 ata1e6721fa, and at1954b64a1before it.check:control-bytesandcheck:new-line-citations(0 new);check-changeset-presence.mjsandchangeset:check;check:pending-changeset-literals,check:self-importandcheck:test-path-roots;check:vi-mock-specifiers,check:vi-mock-inheritandcheck:vi-mock-override-shape;check:spec-symbols,check:phantom-depsandcheck:unreferenced-sources;check:esm-specifiers(specifier leg),check:sdui-registration-pinsandcheck:element-data-source-declaration;check:installed-pin-claims.check:changeset-claims(report-only) named three pending changesets that cite an edited file:6896-…,7546-…and7694-…. Each paragraph was read. Their claims (thecategoriescoverage, the six series keys, thenormalizeSerieslimbs) are untouched. No pending changeset that mentionsspecTypeor the bar default is made false.eslint --no-inline-config --format jsonran over the 4 changed TS files, read as 4 entries: 0 errors.AdvancedChartImpl.tsxhas 44 warnings andnormalizeChartSchema.tshas 5, the same counts as at BASE.no-explicit-anyin thevi.mock('recharts')block, the sibling pattern.eslint.config.jssets noparserOptions.project/projectService, so linting is not type-aware and this diff cannot move a verdict on an untouched file.pnpm lintbelongs to CI.check:doc-types/check:doc-snippets. No doc moved.514d71d1f, seat REWORK5964370972, types only):NormalizedChartSchema['chartType']andAdvancedChartImplProps.chartTypetakeDeclaredChartFamily=NonNullable<ObjectChartSchema['chartType'] | ObjectChartSchema['specType']>, read off@object-ui/typesby reference (already a dependency; no cycle), instead ofstring. There is one named JSON-boundary cast innormalizeChartSchema, and the runtime unknown-type notice is unchanged. Negative compile probe:{ chartType: 'bra' }compiled ata1e6721faand is TS2322 at the new head, while'gauge','pivot'and'sankey'compile.plugin-chartstype-check, the console build (theBundle Analysisprogram) andvitest packages/plugin-charts/(88 files, 1173 passed; matrix 130/130) are green.mainmoved only by a docs commit, so no merge.Acceptance notes
What an accepted document draws changes, so the changeset is
@object-ui/plugin-chartsminor:specTypesingle-value families draw the number card;table/pivotdraw the tabular notice;specType, or no family at all, draws a notice instead of a bar.Every drawn family draws what it drew before, on both keys.
"Located" notice, read as: rendered in the chart's place, naming the value (or saying none was named). There is no console-only signal.
The matrix's node shapes differ from the card's. The card measured three
chartTypespellings, onespecTypespelling and a dimensionless dataset node. This pin puts the family onspecTypein all five shapes, and holds thechartTypechannel to the same answer per family. Its dataset node carries one dimension, so the same mark predicates apply.Docs:
content/docs/plugins/plugin-charts.mdxsays the single-value and tabular families are refused onchartTypeand draw no chart on this node. That is still true, and nothing on the page, in the package README or in the skills states a bar default or aspecTypebehaviour, so no doc moves.Out of scope, reported for the seat to file (class a):
ObjectChart's compare-to gate ischartTypeIgnoresCompareTo(schema.chartType), used for both the comparison fetch and the overlay. It readschartTypeonly.SchemaRenderer, rendered apropertiesbag withcompareTo: { kind: 'previousYear' }and correctly keyed rows. Both documents parse on both faces.chartType: 'scatter': 1 aggregate call, 2 scatter symbols.specType: 'scatter': 2 calls, and thescatter-multi-seriesrefusal ("A scatter plots one measure. Keep exactly one series: amount, amount__comparison").pieonspecTypecosts a wasted comparison fetch with the same picture.ObjectChartreads the resolved family) is not pinned.Noted, not filed:
widgetDispatch.METRIC_LIKE_TYPES(plugin-dashboard) andSINGLE_VALUE_CHART_TYPES(plugin-charts) name the same five families in two packages, with nothing tying them. Undrifted today. Carrier: none.{ type: 'chart', title }widget that names no family. Read from source, not rendered: it now shows the no-family notice whereAdvancedChartImpldrew an empty bar frame.The
compareTogate inObjectChartreadschartTypeonly, so a family onspecTypegets the comparison fetch and overlay:specType: scatterrenders the multi-series refusal, andpiewastes a fetch. Filed by the seat as objectui#11530, sequenced after this PR.Generated by Claude Code