Repository navigation
[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
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".
ManifestInputcarries onlyname/type/of/required/enum/binding/description.validateTree's presence rule isif (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:numberauthoring sites in objectui examples and apps, and 0 in objectstack examples (git greponorigin/main, withelement:textas 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 ofdata/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, likecheckKanbanQuickAddandcheckDashboardWidgetOptions.- 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 intosdui.manifest.json, read byvalidateTreein 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
objectstack-fleet commentedon Sep 28, 2026
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:numberwith anaggregateand 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 ruleinput.required && !(input.name in node),validate.ts:111); no one-of vocabulary enters it, and no per-tag arm entersvalidateTree. 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-localcheckOneOfhelper with a per-family table, ported by lockstep) and C (a component-levelrequiredOneOfmanifest construct,Clause-②: yes) are not taken; D is not opened here.Readings that decided it:
requiredflag 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」, andrequireRecordSource(packages/types/src/zod/objectql.zod.ts:1935) refuses on the JSON door.element:numberjoined that family with PR objectui#10944 and PR objectui#10908 (theproperties.objectarm with thedataSource.objectwaiver). 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.element:numberauthoring sites in objectui examples / apps and in objectstack examples (git greponorigin/main,element:textas 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.@objectstack/lintvalidateComponentProps,dataSource.objectwaiver) already refuse the same node on the metadata path, and because the manifest cannot say "one of" without a new contract.Execution parameters (ruled in the same stroke):
completedwith this ruling; no dispatch.needs-user-decisionleaves;domain:uistays as the lane of record.element:record_picker: unchanged; no card.requiredOneOf?: string[][]onManifestComponent,manifestFromConfigspass-through, amissing-one-ofdiagnostic 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-decisionremoved; card closedcompleted; the Ruled line goes on the body in the same stroke.