feat(spec,lint): <ObjectChart>'s author contract is the spec ChartConfig shape again (#3729) - #3750
Merged
Merged
Conversation
…fig shape again (#3729) #3701 trimmed xAxis/yAxis/series out of the <ObjectChart> contract because the renderer read xAxisKey/series[].dataKey and silently dropped the ChartConfig shapes — an honest record of the runtime gap, not the target state. objectui#2880 closed the gap the other way round (the renderer now honors ChartConfig through one normalization boundary), so the contract follows the protocol again (ADR-0082 D1: the spec schema IS the protocol). Contract: `type`, `xAxis`, `yAxis`, `series`, `subtitle`, `showDataLabels`, `annotations` and `interaction` are published from ChartConfigSchema; the internal chartType/xAxisKey/series[].dataKey spellings leave the author contract. `annotations` and `interaction` gained the .describe() they never had, so the generated contract stops publishing bare `object[]` with no meaning. The `type` exception: ChartConfig.type is the chart family, but on any surface that flattens chart config into a props bag `type` is already the SDUI envelope's component discriminator — an author writing type="bar" used to replace object-chart and the block stopped resolving. The collision is created by the flattening and is resolved there (objectui's react-page wrapper), so the contract can publish `type` as the spec spells it. The generator's blanket `type` skip is now overridable by an explicit dataProps allow-list, since for this one block `type` is a real author prop. Lint: validate-react-page-props reads the axes in the spec spelling — xAxis.field, yAxis[].field, series[].name — and keeps accepting the internal spellings silently, because dashboards and the console's own chart-view wiring emit them. react-chart-axis-inert is retired: the props it warned about are honored now, so the warning would be false. The three binding-integrity rules from #3701 are unchanged. Spec: chart-aggregate.ts records the constraint the whole result-column convention rests on — an inline aggregate is SINGLE-MEASURE. Keying rows by the raw field name only works because there is exactly one measure to key; two measures over one field would collide, and resolving that needs an author-chosen name per measure, which is what a dataset is. The chart taxonomy note is corrected too: grouped/stacked bar and stacked area are absent from ChartTypeSchema not because they render as their base chart, but because stacking is a property of the SERIES (ChartSeries.stack), not a chart family. ChartInteraction.zoom is marked declared-not-delivered rather than reading as shipped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMHZBHTjH4rw8xmDYirFC7
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 104 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 28, 2026 02:00
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 #3729. Depends on objectstack-ai/objectui#2883 — merge that first, then this.
#3701 trimmed
xAxis/yAxis/seriesout of the<ObjectChart>contract because the renderer readxAxisKey/series[].dataKeyand silently dropped the ChartConfig shapes. That was an honest record of the runtime gap, not the target state. objectui#2883 closed the gap the other way round — the renderer honorsChartConfigthrough one normalization boundary — so the contract follows the protocol again (ADR-0082 D1: the spec schema IS the protocol).Contract
type,xAxis,yAxis,series,subtitle,showDataLabels,annotationsandinteractionare published fromChartConfigSchema. The internalchartType/xAxisKey/series[].dataKeyspellings leave the author contract.annotationsandinteractiongained the.describe()they never had — the generated contract was publishing bareobject[]with no meaning, which is not much better than not publishing them.The
typeexception, and a correction to this issue's planThe issue's checklist said "
type取代 overlay 的chartType". That could not be done as written:ChartConfig.typeis the chart family, but on any surface that flattens chart config into a props bag,typeis already the SDUI envelope's component discriminator. An author writingtype="bar"replacedobject-chartand the block stopped resolving.The collision is created by the flattening, so it is resolved there (objectui's react-page wrapper preserves an author
typebeside the discriminator). With that in place the contract can publishtypeexactly as the spec spells it. On this side, the contract generator's blankettypeskip is now overridable by an explicitdataPropsallow-list, since for this one blocktypeis a real author prop.Lint
validate-react-page-propsreads the axes in the spec spelling —xAxis.field,yAxis[].field,series[].name— and keeps accepting the internal spellings silently, because dashboards and the console's own chart-view wiring emit them and they remain a valid (if unpublished) way to write the same binding.react-chart-axis-inertis retired: the props it warned about are honored now, so the warning would be a false positive — the precise thing ADR-0072 D1 says destroys trust in a linter. The three binding-integrity rules from #3701 (react-chart-field-unknown,react-chart-aggregate-invalid,react-chart-axis-unknown) are unchanged in behaviour; they just resolve the axes from more spellings.Spec
The single-measure constraint is now written down (
chart-aggregate.ts). The entire #3701 result-column convention rests on it: keying rows by the raw field name only works because an inlineaggregatecomputes exactly ONE measure. Two measures over one field would collide on the column name, and resolving that needs an author-chosen name per measure — which is what a dataset measure is. WideningChartAggregateSchemainto a measures array would silently invalidate every axis binding these rules validate, so the boundary is recorded rather than left to be rediscovered.Two taxonomy corrections, both of the declared-vs-delivered kind this issue is about:
ChartTypeSchema's note claimed grouped/stacked bar and stacked area were omitted because they render as their base chart. Withseries[].stackhonored that is no longer the reason — and the better reason was always that stacking is a property of the series, not a chart family. Onebarfamily plus a series stack group expresses all three without multiplying the taxonomy.ChartInteraction.zoomnow says in its own description that the default renderer does not implement it andbrushis the shipped alternative, instead of reading as delivered.Verification
@objectstack/spec6710 tests,@objectstack/lint471 tests — all passcheck:react-blocks,check:api-surface,check:skill-refs,check:skill-docs,check:docs,check:spec-changes,check:skill-examplesrenewals-pipeline.page.ts), the skill's analytics guidance and its eval all rewritten to the spec shape; showcaseos validatepasses, and the gate still fires on the new spelling:Follow-up left open
validate-chart-bindings§3 validatesproperties.yAxis[].fieldfor dataset-bound page chart components. objectui#2883 routes the dataset page path through the same normalization, so that rule now checks a prop the renderer really reads — the second of the two out-of-scope findings from #3725 is closed by that PR rather than this one. The first (title/showLegendinert) is closed too: both are honored now.🤖 Generated with Claude Code
https://claude.ai/code/session_01UMHZBHTjH4rw8xmDYirFC7
Generated by Claude Code