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

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions