Skip to content

FieldWidgetPropsSchema 的 JSDoc 仍在教 objectui#3222 裁掉的双份显示:required「visually」+ error「display in its UI」 #5920

Description

@os-zhuang

#4866(PR #5914)收口 content/docs/protocol/objectui/widget-contract.mdx 的教法时发现,未在该 PR 修复 —— #4866 的边界明确写死「不改 packages/spec/src/ui/widget.zod.ts」,而这两句就在那个文件里。按 Prime Directive #10 单独立单。

事实(origin/main 实测)

被修的那份文档,措辞的上游就是 schema 自己的 JSDoc。packages/spec/src/ui/widget.zod.ts:

:459  /**
:460   * Whether the field is required.
:461   * Widget should indicate required state visually and validate accordingly.
:462   */
:463  required: z.boolean().default(false).describe('Required field flag'),
:464
:465  /**
:466   * Validation error message to display.
:467   * When present, widget should display the error in its UI.
:468   */
:469  error: z.string().optional().describe('Validation error message'),

这两句正是 objectui#3222 裁定反对的两件事,而裁定已在 objectui 落地(PR #3289 已合并):

关注点 裁定归属 落地实测
校验消息文案 宿主 < FormMessage / > packages/components/src/renderers/form/form.tsx:1614;widget 侧 packages/fields/src/widgets/types.ts:150-154「a widget reads this ONLY to drive aria-invalid … a widget that also renders it double-displays it」
必填标记 * 宿主 < FormLabel > form.tsx:1484 起;required 干脆不在 objectui 的 widget props 里(spec-symbol-batch7.test.ts_RequiredIsAbsent 钉住)
aria-invalid / aria-required widget 渲染的控件 form.tsx:1574 / :1608

所以 :461 的「indicate required state visually」和 :467 的「display the error in its UI」今天都是反向指导:照做就得到同一句校验文案两遍、同一个星号两遍。这与 #4866 是同一处失实的两层 —— 文档那层已修,schema 这层没动。

为什么值得单独修(即使它不是「用户今天撞到的」)

  • 没有被发布到生成文档:实测 content/docs/references/ 不含这两句(那边只用 .describe()),所以最终用户读不到 —— 危害面是读 schema 源码的人和 AI。而按 AGENTS.md,agent 恰恰被要求去 grep spec 判断契约,spec-property-retirement playbook 也把这个文件当权威。
  • .describe() 不用改:'Required field flag' / 'Validation error message' 都是中性的,是契约可见面,改它才要谈兼容。要改的只有 JSDoc 散文,4 行。
  • 不是契约本身的问题:键名与类型都是对的(fix(identity): close generic-write apiMethods hole on sys_presence & sys_metadata (#3220) #3222 正是按「objectui 跟随 spec」裁的),error?: string 依然是消息本体 —— 只是消费方式是「当信号驱动 aria-invalid」而不是「渲染它」。

建议改法(不改任何键/类型/describe)

required 的 JSDoc 改成:必填标记由宿主的 label 拥有,widget 不要自己画;可反映为控件上的 aria-required(AriaAttributes 已声明该键,无需新增契约键 —— objectui#3290)。
error 的 JSDoc 改成:活动校验消息,字段有效时为 undefined;当信号用(驱动 aria-invalid),文案由宿主渲染,widget 再画一遍就是双份显示。

#5055 的关系(不是它的子集,故独立立单)

#5055 是同一文件的 ADR-0049 enforce-or-remove 决策(target:v18 / pm:on-hold),问的是「这套词表该不该存在」;本单问的是「留着的这两句散文教错了」。无论 #5055 选 A 退役还是 B 给载体,这 4 行都该改,且现在就能改,所以不作为 #5055 的子单。另见我在 #5055 上的评论:PR #3289 之后 FieldWidgetPropsSchema 的推导类型多了一个可测的编译期消费者,那条证据对 #5055 的选项 A 有影响。

关联:#4866、PR #5914、objectui#3222、objectui PR #3289、objectui#3290、#5055


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions