Skip to content

feat(spec,lint): <ObjectChart>'s author contract is the spec ChartConfig shape again (#3729) - #3750

Merged
os-zhuang merged 1 commit into
mainfrom
claude/objectchart-aggregate-naming-nb642o
Jul 28, 2026
Merged

feat(spec,lint): <ObjectChart>'s author contract is the spec ChartConfig shape again (#3729)#3750
os-zhuang merged 1 commit into
mainfrom
claude/objectchart-aggregate-naming-nb642o

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3729. Depends on objectstack-ai/objectui#2883 — merge that first, then this.

#3701 trimmed xAxis/yAxis/series out of the <ObjectChart> contract because the renderer read xAxisKey/series[].dataKey and 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 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 — the generated contract was publishing bare object[] with no meaning, which is not much better than not publishing them.

The type exception, and a correction to this issue's plan

The issue's checklist said "type 取代 overlay 的 chartType". That could not be done as written: 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" replaced object-chart and the block stopped resolving.

The collision is created by the flattening, so it is resolved there (objectui's react-page wrapper preserves an author type beside the discriminator). With that in place the contract can publish type exactly as the spec spells it. On this side, the contract 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 and they remain a valid (if unpublished) way to write the same binding.

react-chart-axis-inert is 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 inline aggregate computes 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. Widening ChartAggregateSchema into 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. With series[].stack honored that is no longer the reason — and the better reason was always that stacking is a property of the series, not a chart family. One bar family plus a series stack group expresses all three without multiplying the taxonomy.
  • ChartInteraction.zoom now says in its own description that the default renderer does not implement it and brush is the shipped alternative, instead of reading as delivered.

Verification

  • @objectstack/spec 6710 tests, @objectstack/lint 471 tests — all pass
  • All seven generated-artifact gates in sync: check:react-blocks, check:api-surface, check:skill-refs, check:skill-docs, check:docs, check:spec-changes, check:skill-examples
  • Golden page (renewals-pipeline.page.ts), the skill's analytics guidance and its eval all rewritten to the spec shape; showcase os validate passes, and the gate still fires on the new spelling:
✗ React-source page prop check failed (1 issue)
  • page "showcase_renewals_pipeline" › <ObjectChart>: "sum_total" is not a column this
    aggregate returns, so the axis plots nothing. Object-bound aggregate rows are keyed by
    the RAW FIELD NAMES (unlike a dataset, whose rows are keyed by measure name).

Follow-up left open

validate-chart-bindings §3 validates properties.yAxis[].field for 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 / showLegend inert) is closed too: both are honored now.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UMHZBHTjH4rw8xmDYirFC7


Generated by Claude Code

…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
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 28, 2026 1:49am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests protocol:ui tooling labels Jul 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/lint, @objectstack/spec.

104 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/lint, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 28, 2026 02:00
@os-zhuang
os-zhuang merged commit 4f740b0 into main Jul 28, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/objectchart-aggregate-naming-nb642o branch July 28, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

图表绑定方言统一:ObjectChart 运行时兑现 ChartConfig 后,把 react 契约与 lint 切回 spec 形状(#3701 后续)

2 participants