Skip to content

normalizeFilterOptions accepts a bare-string globalFilters[].options shorthand that @objectstack/spec rejects at publish #4356

Description

@yinlianghui

Found while implementing #4032 (binding DashboardComponentSchema.globalFilters to the spec's GlobalFilter). Not fixed there — that card's scope is the I18nLabel widening, and removing a tolerated shorthand is a behaviour change on stored metadata with its own migration question.

The divergence

@object-ui/core's normalizeFilterOptions (packages/core/src/utils/dashboard-filters.ts) documents and accepts two option forms:

the @objectstack/spec GlobalFilterSchema.options form is { value, label } objects; the bare-string shorthand (options: ['EMEA', …]) is also accepted

The spec accepts only the first. Measured against @objectstack/spec@17.0.0-rc.6:

DashboardSchema.safeParse({ …, globalFilters: [{ field: 'region', type: 'select', options: ['EMEA', 'APAC'] }] })
→ ["Invalid input: expected object, received string",
   "Invalid input: expected object, received string"]

… options: [{ value: 'emea', label: 'EMEA' }]
→ ACCEPTED

So a dashboard authored with the shorthand renders correctly in objectui and is refused the moment it reaches the platform's validation. That is the "one strict contract beats N dialects" case AGENTS.md #0.1 names: a renderer-side tolerance that has quietly become a second de-facto contract, and it hides the producer's bug rather than surfacing it.

What #4032 already changed, and what it deliberately did not

#4032 bound the TYPE to the spec, so the shorthand is now a tsc error at authoring — that half is done and pinned in packages/types/src/__tests__/dashboard-global-filters-spec-binding.test.ts. The RUNTIME tolerance is untouched: normalizeFilterOptions still lifts a bare string, because already-persisted dashboards may carry one and dropping them silently would turn a rendering filter into an empty one.

The decision this needs

  1. Keep the runtime lift permanently, and get the spec to admit the shorthand (it is a genuinely convenient authoring form) — i.e. fix the divergence at the contract.
  2. Retire the lift behind a deprecation window: warn on a bare string now, remove later. Needs a survey of stored dashboards first.
  3. Retire it immediately — only defensible if no stored dashboard uses it.

No repo source authors the shorthand today (grepped packages/, apps/, examples/), so the local blast radius is zero; the unknown is customer metadata.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepm:blocked

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions