Uh oh!
There was an error while loading. Please reload this page.
feat(spec): RecordHighlightsField 声明 readonly —— 渲染器已强制的键不再被静默剥离 (#5176) - #5607
Conversation
`record:highlights` 条目的对象形式新增可选 `readonly: boolean`,用于把高亮
chip 标记为不可行内编辑(hook / 自动化维护的列)。
此前该键未被声明,而对象成员不是 `.strict()`,因此被**静默剥离**:
input { fields: [ { name: 'supply_share', readonly: true, type: 'number' } ] }
parsed { fields: [ { name: 'supply_share', type: 'number' } ] }
今天之所以端到端可用,只是因为逐组件 props 尚未在装载路径上解析
(`PageComponentSchema.properties` 是 `z.record(z.string(), z.unknown())`)。
一旦该闸门接通,授权的 `readonly` 要么静默丢失(机器维护列重新可编辑、
零诊断),要么硬解析失败。声明它使"授权的声明"与"被强制的行为"成为
同一事实 —— 落地即满足 ADR-0049 enforce-or-remove,而非声明即惰性。
纯增量:`readonly` 可选且不物化默认值,未授权该键的条目解析结果与此前
完全一致;bare-string 形式不变。对象级 `highlightFields: string[]` 不在
本次范围内。
不翻 `.strict()` —— 那属于 #5068 的闸门专项。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6DThe latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 109 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
commented
Aug 5, 2026
PM 预记( Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#5176
按维护者 2026-08-05 裁定的 Option A 实施,仅 spec 侧。
改了什么
packages/spec/src/ui/component.zod.ts中RecordHighlightsField的对象成员新增一个已声明键:union 形状本身不动(bare-string 成员不变),不翻
.strict()—— 那属于 #5068 的闸门专项,明确不在本单范围。对象级的highlightFields: string[]同样未触碰(见 issue 的范围边界)。同时把两处
.describe()里已经过时的形状说明补齐({name,label?,icon?,type?}→{name,label?,icon?,type?,readonly?}),否则生成的组件参考文档会描述一个与 schema 不符的形状。前提复核(rule 6):issue 前提成立,已实测复现
在
origin/main(e900015cd)上按 issue 所述逐条核对:union 为[string, object]、对象成员非.strict()、readonly缺席且被静默剥离。剥离实测(改动前跑新增的保留测试):即
{ name: 'supply_share', readonly: true, type: 'number' }解析后readonly为undefined—— 与 issue 正文给出的 input/parsed 对照完全一致。先证红 → 后转绿
按"先写测试证红"的要求,先写保留测试并在未修改的 schema 上跑红,再改 schema。事前预判的方向是常规红(删掉
readonly这条 limb,新增的 pin 测试转红),实际与预判一致:改动前(5 个新增用例中 3 红 / 2 绿):
另外 2 个用例(
不物化默认值、bare-string 与其它对象形式仍被接受)是回归护栏,改动前后都应绿,实测也确实都绿 —— 它们不承担证红职责,如实标注。改动后(spec 全量):
其中
should reject a non-boolean readonly这一条值得单说:改动前readonly: 'yes'会被静默剥离从而通过解析,改动后 union 两个成员都失配、解析响亮失败 —— 这正是裁定里"拼写/类型错误在闸门接通后响亮失败"的那一半,现在在 schema 层就已兑现。消费半径清扫
record:highlights的下游读取方是packages/lint的validate-page-field-bindings.ts(COMPONENT_FIELD_SPECS['record:highlights'] = { props: ['fields'] })与validate-react-page-props.ts,两者只从条目中取name;本次是纯增量、未删除任何 limb,因此不存在需要重判的 fixture(fixture 三分类处置在此无适用项)。全仓 grep 也确认没有任何 fixture 拼写过readonly。packages/lint全量:59 passed (59) / 1284 passed | 4 skipped。生成物审查
content/docs/references/ui/component.mdx—— 本 PR 内唯一应当移动的生成物,三处改动逐行可由这一个键解释:union 描述行、对象成员表新增readonly行、fields行内类型因生成器满 4 个属性后截断而显示省略号。api-surface.json—— 未移动,已实测确认(public API surface + factory signatures unchanged ✓)。该文件只记录"名字 (kind)"字符串,不含类型文本,而本次未新增导出,因此结构上不可能移动。authorable-surface.base.json—— 已git checkout排除,不入本 PR(check:authorable-surface在--check模式下也会重写authorable-surface.base.json—— 一次纯核验会改工作区,且任何无关 PR 都能因此静默推进删除门的锚点 #5358 纪律)。gen:schema会把它刷新到新 baseRev 并顺带吸收 3 个与本单无关的键(system/EmailServiceConfig:appName/defaultTemplateContext/queueDelivery,来自其它已合入 issue)。注意:它不含本次新增的readonly。check:spec-changes/upgrade-guide/skill-refs/skill-docs/skill-examples/react-blocks/react-declaration-parity/variant-docs/empty-state/strictness-ledger/liveness/doc-authoring/docs-audit-scope/nul-bytes)全绿,未新增任何check:/gen:脚本,故无需登记 check-generated 台账。一处对派发预设的更正
派发说明预期"
component.zod.ts在 #5068 中实测 BFS 不可达,故 authorable-surface 不应移动"。结论(不移动)对,但理由需更正:ui/RecordHighlightsProps:fields本身在该 walk 里。真正的原因是这个 walk 是严格一层的 —— 全表 1080 个ui/键中带嵌套路径的为 0(RecordRelatedListProps:add同样只记容器、不下钻add.picker.object)。readonly挂在fields数组项 union 的对象成员上,属于第二层,因此不产生新的 authorable-surface 键。对 #5068 实施者而言这是个有意义的差别:该键不会自动进入 authorable 面,闸门接通时需按 props 解析路径单独覆盖。验证命令
check:api-surface与check:skill-examples在新工作树里初次为红,原因是尚未build出dist/(闸门自身即提示 "this gate reads the BUILT dist ... the removals above are phantoms");建包后两者均转绿,与本改动无关。Changeset
@objectstack/specminor(新增已声明协议键,additive)。后续项(不在本 PR)
record:highlightsblock 的inputs中声明readonly,使其进入sdui.manifest.json—— 裁定中明确可另 PR,由 objectui 车道承接。在此之前,AI 作者仍无法从 manifest 学到该键(docs/audits/2026-06-react-blocks-conformance.md记为 "zero inputs")。readonly)按裁定保留为后续便利层,未并入。Generated by Claude Code