Skip to content

RecordDetailsProps 与真实页面的授权形状不符:sections 声明为 string[] 但所有页面授权对象形式,hideFields 完全未声明 #5611

Closed

Description

@os-zhuang

实施 #5176(为 RecordHighlightsField 声明 readonly)时,按"规则消费半径"清扫 packages/lint 下游读取方发现的范围外问题 —— 与 #5176 同一族(声明与授权不一致,靠 props 无解析闸门苟活),但不是同一个键,故另开。未在 #5176 的 PR #5607 中修复。

实测

packages/spec/src/ui/component.zod.ts 的 RecordDetailsProps 声明键为:columns / layout / sections / fields / aria。

其一 —— sections 的类型与所有真实授权相反。 声明是"分区 ID 列表":

sections: z.array(z.string()).optional().describe('Section IDs to show (required when layout is "custom")'),

而仓库里每一个真实页面授权的都是对象形式的分区(带 label / columns / 嵌套 fields[]):

  • examples/app-showcase/src/ui/pages/project-detail.page.ts:49
  • examples/app-showcase/src/ui/pages/settings.page.ts:27
  • examples/app-showcase/src/ui/pages/task-detail.page.ts:73
sections: [
  { label: 'Overview', columns: 2, fields: ['name', 'account', 'owner', 'status'] },
  { label: 'Financials', columns: 2, fields: ['budget', 'spent'] },
],

仓库自己的 lint 也是按对象形式建模的 —— packages/lint/src/validate-page-field-bindings.ts:166 把 sections 登记为 nestedSections,其类型注释明确写着"holding {...}[] section objects whose fields[] are field names"。

其二 —— hideFields 未声明,但被一个已发布的平台页授权:packages/platform-objects/src/pages/sys-user.page.ts:106。

两者今天都能跑通,原因与 #5176 完全一致:PageComponentSchema.properties 是 z.record(z.string(), z.unknown()),逐组件 props 从不被 parse(#5068 的判定)。lint 源码里那行注释把这个事实说得很直白:"sections/hideFields are not in RecordDetailsProps, but every real page authors them (they survive because properties is unvalidated)"。(该注释关于 sections 的部分现在略有偏差:sections 是已声明的,只是类型对不上;hideFields 才是完全未声明。)

为什么现在就值得处理

需要裁定的方向

不自行猜测,列出选项:

  • A:把 spec 改成与真实授权一致 —— sections 改为 z.array(SectionObject)(或 z.union([z.string(), SectionObject])),并声明 hideFields。收益:声明与被兑现的行为成为同一事实,无需迁移任何现存页面;代价:sections 的类型变更对任何真按 ID 列表授权的存量数据是破坏性的(需先确认是否存在这类数据)。
  • B:把页面改成与 spec 一致 —— 三个 showcase 页面 + 平台页改写为 ID 引用形式。代价:需要渲染器真的支持 ID 引用形式(未经证实),且要为 hideFields 另找归宿;基本等于推翻现行事实标准。
  • C:按 ADR-0087 D2 声明成转换层 —— 若两种形状都要长期支持。

倾向 A,与 #5176 同样的两轴理由:声明与强制合一,且不需要一次跨仓迁移。但 sections 是既有已声明键、改类型带破坏性,超出我的判断范围,故不动、只记录。

关系

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 5, 2026
  2. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    PM 分诊(spec 车道,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05):进决策位(needs-user-decision)——sections 是既有已声明键的类型变更,属公开契约形状分歧,过升级门槛。两轴分析与建议如下,可一句话批。

    建议:A 的收紧变体 —— sections 直接改为对象形式数组(z.array(SectionObject)),不做 union、不做 C 转换层;hideFields 声明为 z.array(z.string()).optional()。


    Generated by Claude Code

  3. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    维护者裁定(2026-08-06,经 spec 车道 PM session_018fxLGQdatPbBUvCgiVxg6D 誊写):A 收紧变体——sections 直改对象形式数组(不做 union、不做 C 转换层),hideFields 声明为 z.array(z.string()).optional()。派发前置照 PM 分诊注记执行:dev 先测 ID-list 形式在 objectui 有无读取点,有则停手回报改裁。摘 needs-user-decision,即刻派发。#5068 的 error 升级前置由此解除(其 warning 阶段本就不等)。


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 6, 2026
  5. self-assigned this
    on Aug 6, 2026
  6. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    PM 认领(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-06)


    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

Labels

domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions