Skip to content

[Decision] Should the html tier report a one-of record source again (element:number's object or dataSource.object, record_picker, calendar and gantt)? The sdui manifest cannot say "one of" today #10991

Description

@objectstack-fleet

Ruled: 5872049943 · letter A (no authoring-time one-of report; runtime notice via PR #10989 is the answer; card closed) · 2026-09-28T14:30Z

维护者速读 · decision: restore an authoring-time report for "one of two ways to name the object"? · domain:ui seat 2 · 2026-09-28

Filed by domain:ui seat 2, session_014mXUNuFomfj24w7s1pZzhN. Triage 5869415559 on objectui#10951 routes it here: "(b) only if the manifest can already say one-of … It cannot: ⛔ don't invent a manifest construct here. Stop and report it as needs_decision; objectui#10508's calendar and gantt trade would ride on the same answer." objectui#10951's runtime half (a) is in PR objectui#10989: an element:number with an aggregate and no object now shows a localized "no object named" notice instead of a silent "—". This card carries only the authoring-time half.

The question. PR objectui#10944 made element:number accept its object from dataSource.object, so object stopped being required. Before that, the html tier (validateTree: the JSX page compiler, the save gate and the objectstack CLI's JSX gate) reported a node with no object. Should a node that names neither be reported at authoring time again?

Measured (dev report 5871269526 on objectui#10951):

  • The sdui manifest input model cannot express "one of". ManifestInput carries only name / type / of / required / enum / binding / description. validateTree's presence rule is if (input.required && !(input.name in node)), and its per-tag checks are hard-coded in the parser, not registration hooks.
  • objectstack runs a lockstep port of packages/sdui-parser/src, so any parser or manifest change lands in both repos.
  • Reach: 0 non-test element:number authoring sites in objectui examples and apps, and 0 in objectstack examples (git grep on origin/main, with element:text as the lit control). The producer at risk is AI page authoring, which is not measured.
  • The same answer decides element:record_picker (object or binding) and the calendar and gantt record source of objectui#10508 (one of data / staticData / objectName).

Options, on the four axes:

  • A (recommended). Keep the runtime notice (PR objectui#10989), and add no authoring-time check.
    • Business need: 0 measured authoring sites.
    • Long-term: no new contract. The author sees the notice when the page renders, not at save, which is later than before PR objectui#10944.
    • AI-error: the mistake is visible, not silent, but nothing refuses it at publish.
    • Startup focus: no new surface and no new gate.
  • B. A parser-local per-tag rule in validateTree, like checkKanbanQuickAdd and checkDashboardWidgetOptions.
    • Business need: the same as A.
    • Long-term: one hard-coded arm per one-of family (element:number, record_picker, calendar, gantt), each a two-repo lockstep change. This is the workaround shape.
    • AI-error: a loud refusal on both JSX doors once ported.
    • Startup focus: a new gate no maintainer has named, so the default is no.
  • C. One new manifest input-model construct: a component-level required-one-of list that can name a nested path such as dataSource.object. It is serialized into sdui.manifest.json, read by validateTree in both repos, and declared by the four families.
    • Business need: the same as A.
    • Long-term: the contract-first shape. One declaration replaces N parser arms and restores the report objectui#10944 lost.
    • AI-error: the strongest, since what is declared is enforced at publish.
    • Startup focus: it widens a published contract (Clause-②: yes, the lockstep port, codegen and type readers) and adds a gate the maintainer has not named.

The seat recommends A. Nothing measured pulls for an authoring-time refusal, and a new gate or contract surface defaults to no until the maintainer names one. If the maintainer does want the refusal back, choose C over B: one contract-first construct covers all four families, where B repeats a parser arm per family in both repos.

After the decision: A closes this card with no code change. B or C each become a dispatchable card, and C also needs the objectstack lockstep port.

domain:ui seat 2 · decision card · 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

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions