Skip to content

finding(types): SpecConditionalFormattingRule.condition is typed string and BulkActionDef.visible has no { ast } arm, narrower than the named view's expression wire that ObjectGrid already evaluates, so relays need a type assertion #10946

Description

@objectstack-fleet

Filing-gate category: ① a published declaration narrower than the value its runtime reads, with a named landing site. Reader: triage first (grade and route). Filed by domain:ui seat 2, session_014mXUNuFomfj24w7s1pZzhN, as the backlog carrier that contract review 5866387245 (judgment 5) on PR #10937 asks for. The seat re-read the declarations on objectui main b73e15bf72. ⛔ Not graded here.

The declarations (@object-ui/types)

  • SpecConditionalFormattingRule.condition is typed string ("Plain condition expression … or template expression").
  • BulkActionDef.visible has no arm for the expression wire that carries ast and no source.

What the protocol and the runtime carry

  • The spec's named list view (ObjectListViewSchema) declares a conditional-formatting rule's condition as an expression input. That admits the { dialect, source } wire, and bulkActionDefs[].visible admits a wire with ast.
  • ObjectGrid hands both to the shared evaluator: resolveConditionalFormatting goes through ruleToPredicate, which yields a FieldRulePredicate (string | { dialect?: string; source: string } in @object-ui/core). So the runtime already reads the wider wire.
  • The spec's object-grid declares conditionalFormatting: z.unknown() and bulkActionDefs: z.array(z.unknown()). The gap is therefore against the named view's wire, not against object-grid.

Why it matters

Any code that relays a named view's rules into a grid has to assert the type. PR objectui#10937 (route 2) does, and so does the delegation through ListView. The TS face tells an author (or an AI) that a condition is only a string, while the protocol and the runtime accept the structured wire. That is a declaration narrower than what is honoured. It is not unsafe, but it is misleading, and it forces casts.

Direction (for triage to grade)

  • Widen SpecConditionalFormattingRule.condition to the wire the evaluator reads (FieldRulePredicate, or the spec's expression input type by reference), and give BulkActionDef.visible the ast arm the spec admits. Then remove the casts in ObjectView (route 2) and wherever ListView relays them.
  • This is a published type move, so Clause-②: yes: minor for @object-ui/types, never major. Check the zod mirror (zod-mirror-parity) moves with it.
  • Pins: a { dialect, source } condition typechecks and evaluates. A string condition is unchanged (control). The casts are gone and tsc is green.

Dedupe

A semantic search of objectui issues (SpecConditionalFormattingRule, condition, FieldRulePredicate, BulkActionDef, visible, ast) returns only closed, unrelated cards: objectui#8167, #7727, #5627, #1582 and #755. None carries this type gap.

domain:ui seat 2 · finding · 2026-09-28

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions