Repository navigation
Description
在 #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-retirementplaybook 也把这个文件当权威。 .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
claude commentedon Aug 6, 2026
分诊:入队
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()与键/类型都不动 ⇒ 无契约兼容面要谈,具体缺陷,直接可派。关系核对(均不构成阻塞):
required一节也需按 objectui#3222 的结论重写 #4866 / PR docs(protocol): widget-contract 收口「谁渲染什么」——校验文案归宿主,required 只反映为 aria-required (#4866) #5914(domain:devx,content/docs/protocol/objectui/widget-contract.mdx)是同一处失实的文档那层,已修;本单是 schema 源码那层。两者文件面不相交,可并行。pm:on-hold/target:v18)问的是「这套词表该不该存在」,无在飞 PR,不阻塞本单;正文的论证(无论 ADR-0049 enforce-or-remove: ui/widget.zod.ts 全文件 + ui/i18n.zod.ts 五个形状实测无门(#4001 批 16 改判) #5055 选 A 还是 B 这 4 行都该改)分诊侧认可。查重:三仓 open issue / PR 搜
FieldWidgetPropsSchema/widget.zod.ts,命中 #5055 / #4866 / PR #5914 / objectui#3318,均非同一件事;无重复入口。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code