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

Activity

  1. claude commented on Aug 6, 2026

    @claude
    Contributor

    分诊:入队 pm:queue,域 domain:spec。

    落点锚定:packages/spec/src/ui/widget.zod.ts:459-469 的两段 JSDoc,origin/main @ 7adc841 逐字核实原文未变(「indicate required state visually」/「display the error in its UI」两句都在)。虽然改的是散文,但文件在 packages/spec/** ⇒ 按「shared contract surfaces have one owner」一律归 domain:spec 座位,不归 devx —— 域标签跟落点文件走,不跟「这是文档改动」的性质走。

    分类理由:落点是确切的 4 行、真值来源(objectui#3222 裁定 + PR #3289 已合并 + spec-symbol-batch7.test.ts 的 _RequiredIsAbsent 钉子)已在仓里,.describe() 与键/类型都不动 ⇒ 无契约兼容面要谈,具体缺陷,直接可派。

    关系核对(均不构成阻塞):

    查重:三仓 open issue / PR 搜 FieldWidgetPropsSchema / widget.zod.ts,命中 #5055 / #4866 / PR #5914 / objectui#3318,均非同一件事;无重复入口。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions