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

Closed

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

  1. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #239 item 1 · letter A · maintainer 「同意」 2026-09-28T14:29Z

    Director seat (objectstack#12708, summon #30 续 2, session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying 「同意」 to batch #239 as presented — this card item 1, recommendation A, fallback C, B not recommended, D (the html tier running the zod door over the compiled tree) named as out of this card, the full four-axis body in chat.

    Ruled: A. The html tier adds no authoring-time report for "one of two ways to name the object". The runtime notice (PR objectui#10989: an element:number with an aggregate and no object in either place draws a localized 「no object named」 state instead of the silent dash) is the answer to objectui#10951, and it is the whole answer. The sdui manifest stays the coarse contract it is (name / type / of / required / enum / binding / description; presence rule input.required && !(input.name in node), validate.ts:111); no one-of vocabulary enters it, and no per-tag arm enters validateTree. The same answer settles the sibling families: element:record_picker (object or binding) and the calendar / gantt record source of objectui#10508 stay as they are. B (a parser-local checkOneOf helper with a per-family table, ported by lockstep) and C (a component-level requiredOneOf manifest construct, Clause-②: yes) are not taken; D is not opened here.

    Readings that decided it:

    • Long-term: this is the design objectui#7470 / objectui#10392 already chose for map, gantt and calendar — the required flag left the registration, the docblock says 「no one-of vocabulary is added to the input declaration; the zod refinement stays the place that enforces it」, and requireRecordSource (packages/types/src/zod/objectql.zod.ts:1935) refuses on the JSON door. element:number joined that family with PR objectui#10944 and PR objectui#10908 (the properties.object arm with the dataSource.object waiver). One family, one shape; C would have been the contract-first alternative and is recorded as the shape to take if the refusal is ever wanted back — never B.
    • Real use: 0 non-test element:number authoring sites in objectui examples / apps and in objectstack examples (git grep on origin/main, element:text as the lit control); the mistake is visible wherever the page renders once objectui#10989 lands. AI page authoring is the producer at risk and is NOT MEASURED.
    • AI-safety: the weakest axis for A, stated plainly: a JSX page naming no object saves and publishes clean on the html tier and is caught at render, not at publish. Accepted because the JSON door and the spec's props gate (@objectstack/lint validateComponentProps, dataSource.object waiver) already refuse the same node on the metadata path, and because the manifest cannot say "one of" without a new contract.
    • Startup scope: no new gate (「新增门禁默认否」 holds; nothing measured pulls for the exception), no contract widening, no lockstep regeneration; the card closes with no code.

    Execution parameters (ruled in the same stroke):

    • This card closes completed with this ruling; no dispatch. needs-user-decision leaves; domain:ui stays as the lane of record.
    • objectui#10951: (b) is settled by this ruling (one line goes on that card); its seat lands PR objectui#10989 for (a) and closes the card on that PR.
    • objectui#10508's calendar / gantt trade and element:record_picker: unchanged; no card.
    • Recorded, not opened: C is the shape if an authoring-time one-of report is ever wanted (one requiredOneOf?: string[][] on ManifestComponent, manifestFromConfigs pass-through, a missing-one-of diagnostic naming both spellings, four family declarations, lockstep regeneration); D (the JSX doors handing the compiled tree to the zod door / the spec props gate) is a separate question about the html tier as a whole and is not filed by this ruling.

    State: needs-user-decision removed; card closed completed; the Ruled line goes on the body in the same stroke.

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