Skip to content

[finding] objectstack's copy of CONSUMED_WIDGET_OPTION_KEYS is pinned, not derived — a new declared key in DashboardWidgetOptionsSchema turns the port into a false positive on legal metadata, silently #12926

Description

@os-elon

Filed by the domain:devx dev seat while porting dashboard-widget-options for #12810. The port is correct as landed; this records a drift hazard it necessarily leaves behind, so it is findable rather than living only in a file header.

The hazard

checkDashboardWidgetOptions warns on any widget options key outside CONSUMED_WIDGET_OPTION_KEYS. That array has two halves:

  • the five DECLARED keysdateGranularity, sortBy, sortOrder, limit, stageOrder — which are exactly the five properties DashboardWidgetOptionsSchema declares in packages/spec/src/ui/dashboard.zod.ts;
  • description — undeclared, but written into options by translateDashboard (documented on WidgetLike.options in packages/spec/src/system/i18n-resolver.ts).

In objectui, the array is re-derived every test run against the installed spec and against the renderer's read sites. In this repo it is a literal pin. So the failure mode is specific and one-directional: someone adds a declared key to DashboardWidgetOptionsSchema — a change entirely inside THIS repo, since the spec ships from here — and does not touch the parser. The new key is then spec-legal, renderer-consumed on the objectui side, and warned about here. A false positive on legal metadata, which is the shape that gets a diagnostic deleted by the next person who hits it.

Why the existing test does not catch it

The test added with the port asserts the array equals the six expected strings and names the two spec files to re-read. That pins the parser against ITSELF. Adding a key to the spec does not fail it — the test stays green and becomes wrong, which is precisely the "closure claim nothing re-derives" pattern this repo treats as a defect elsewhere.

Why the port did not just derive it

@objectstack/sdui-parser takes no dependency on @objectstack/spec — it is dependency-free and hoistable by design, and its package.json devDependencies are only typescript and vitest. Adding the spec as a test input is not a one-line change: it pulls the package into check:cross-package-test-inputs (a turbo.json inputs declaration) and into check:test-source-alias (a vitest alias or a KNOWN_UNALIASED_TEST_IMPORTS registration). That is a real design decision about the package's purity, well outside a port's scope, so it was not taken unilaterally.

Options, none chosen here

  • Derive in a gate script instead of a test — a scripts/check-*.mjs reading both files by source text keeps the package dependency-free and puts the claim where the repo already keeps cross-package claims. Probably the cheapest honest answer.
  • Take the devDependency and derive in-package like objectui does, accepting the two gate registrations.
  • Accept the pin and rely on the header note. Cheapest, and the option that decays — worth choosing explicitly rather than by default.

Note the whole class is currently latent for a second reason, recorded separately: validateTree is not reached from the production gate at all (#12924). A false positive here would surface only once that wiring lands, which is an argument for settling this before it does, not after.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions