Skip to content

[移交自 objectui] 登记 ADR-0087 D2 conversion 条目 page-header-subtitle-alias(description → subtitle) #4827

Description

@xuyushun441-sys

Part of objectstack-ai/objectui#3226

按 /pm-dispatch 的跨分片移交协议从 objectui 分片转来:共享契约面(packages/spec / ADR-0087 conversion 机制)单一 owner 是主 backlog PM,objectui 分片 PM 不自行派发。

要做什么

登记一条 ADR-0087 D2 conversion-layer 条目 page-header-subtitle-alias:加载时把 page-header 节点上的 description 改写成 canonical 的 subtitle。

背景(为什么是 conversion 而不是直接删)

objectui 的 page-header(kebab 遗留别名,@object-ui/layout)与 page:header(协议键,canonical,@object-ui/components)对同一个"页面副标题"概念声明了两套 authorable 键:前者 description,后者 subtitle。消费端用一个裸 ?? 兜底(const secondaryRaw = subtitle ?? description;),这正是 Prime Directive #12 说的"producer 写错、consumer 用 ?? 兜住"。

@objectstack/spec 的 PageHeaderProps 声明的是 subtitle。

关键判断:不能走"直接删 description"路线。 objectui 侧两任 PM 独立复核后一致:

该别名存在的全部理由就是仓外的消费者 schema(注册点注释原文:Legacy page-header alias. Kept for any consumer schemas that still…)。因此"objectui 仓内 grep 不到 description"与"没人在写"是两回事 —— 恰恰在这个别名上,仓内证据的覆盖面为零。

实测确认 objectui 仓内零命中(其余 page-header 命中都是 report designer 的同名不同概念、placeholder 清单、注册点自身、data-testid、CHANGELOG)。但按删除路线走,外部写 description 的页面会静默丢副标题 —— 标题照常渲染、只是第二行消失,是最难被报障的失效形态。

已经在 objectui 侧做掉的半边

objectui#3226 已派发并限定范围为只收窄声明面:让 page-header 的 registration inputs 不再宣告 description。理由是它在两条路线下都成立,而且是今天危害最直接的一半 —— inputs 是设计器与 check:react-declaration-parity 这类工具读取的声明面,等于注册声明在教作者写一个非 spec 的键。该改动不动运行时(裸 ?? 保留),对仓外消费者零破坏。

本单落地后,objectui 侧的收尾(届时由 objectui 分片 PM 派)

conversion 条目落地并随 spec 发布后,objectui 才能删掉 PageHeader.tsx 的 subtitle ?? description 与 description prop,消费端只读 subtitle。objectui#3226 会挂 Blocked-by 指向本单。

参考位置(objectui 侧,供对照)

  • packages/layout/src/index.ts — ComponentRegistry.register('page-header', …) 的 inputs
  • packages/layout/src/PageHeader.tsx — subtitle? / description? 与 subtitle ?? description
  • packages/components/src/renderers/layout/containers.tsx — canonical page:header,只读 subtitle

关联:objectui#3226、objectui#3223、objectui#3161 / #4115 batch 7、ADR-0087 D2、Prime Directive #12

Activity

  1. self-assigned this
    on Aug 5, 2026
  2. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    认领:spec 车道第 2 批
    会话:session_018fxLGQdatPbBUvCgiVxg6D
    分支:claude/issue-4827-page-header-subtitle-conversion
    Worktree:objectstack-issue-4827
    域:domain:spec
    文件面:packages/spec/src/conversions/**(registry + 实现 + 测试)+ 生成物(spec-changes.json 等)。

    范围:仅登记 D2 conversion page-header-subtitle-alias(description → subtitle,page-header 节点,加载期改写)。objectui 侧收尾(删 ?? 兜底)由 objectui 分片在本单落地后按其 #3226 的 Blocked-by 推进,不在本单。


    Generated by Claude Code

  3. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    实现已推,draft PR:#5509。

    顺带记一条给 objectui 侧收尾用的定价输入,不影响本单的完成判据,但会影响 objectui#3226 那一步的充分性判断:

    本条目改写的是走 ObjectStack 加载路径的 page 元数据 —— normalizeStackInput(defineStack / validate / lint)以及 applyConversionsToStoredItem 覆盖的 sys_metadata page 存量行。这两条路都覆盖到了(存量行那条有专门用例钉着)。

    但本单背景里说的「别名存在的全部理由是仓外消费者 schema」有一种形态是本条目够不着的:如果那些消费者 schema 是直接交给 objectui 的 SchemaRenderer 渲染的 SDUI 文档,而不是作为 ObjectStack page 元数据入库/加载,那它们根本不经过 conversion 层,description 也就不会被改写。对这一类消费者,删掉 PageHeader.tsx 的 subtitle ?? description 仍然会静默丢副标题 —— 正是本单开头要避免的那种失效形态。

    所以 objectui#3226 收尾前值得先答一个事实问题:那些仍在写 description 的消费者 schema,是经 ObjectStack 元数据加载的,还是直接喂给 SchemaRenderer 的? 前者本单已解决;后者需要 objectui 侧另想办法(例如渲染器侧一次性的 conversion 等价物,或者干脆保留读一段时间)。

    我没有替 objectui 分片做这个判断,也没有为此另开单 —— 它属于 objectui#3226 的范围,记在这里让接手的人不必重新发现。


    Generated by Claude Code

  4. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    验收(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D):ACCEPT → PR #5509(draft;CI 中 Temporal Conformance 的红已定因为纯基础设施抖动 —— mongodb-memory-server 二进制下载超时后,被弃下载流的 ENOENT rename 成为 unhandled rejection,282 用例 0 失败 —— 已原样重跑;全绿后转 ready 入队)。

    验收要点:

    1. 条目按 ADR-0087 D2 live-window 惯例落齐四件套(conversion + D3 链 step 17 + spec-changes/升级指南重生成 + changeset),胜负语义照抄 renameKey 房规不发明 ✓;
    2. 两个 reviewer 判断都批准:双拼写都转(canonical 侧的 description 今天就是被扔在地上,同缺陷不同拼法)、不改写 type(开放命名空间上的 type 改写正是需要冲突守卫的那类动作,别名存废归 objectui);
    3. 反向验证的「见证者 vs 守卫」区分是本轮最有价值的方法论输出:场景 A 揭示逐条 fixture/chain-replay 测试在条目被摘时消失而非变红(for (const c of ALL_CONVERSIONS) 驱动),场景 B 证明登记完整性门与行为门互不替代;预测偏差(11 红 → 实际 4 红)如实报账;
    4. 越范围三笔全部核实:conversions:page-component-visibility-to-visibleWhen 就地展开了 region→components 的 copy-on-write 走查,与新的 mapPageComponents 是两份同形代码 #5511(walk 双实现漂移风险,finding 持有)、build-schemas.ts 检查 (b) 用叶名匹配 conversion surface —— 无关簇的 .type 就能让一个 tombstone 冒充「已登记迁移」 #4659 追记(description 进 endsWith 词表,既有缺陷不另立单)、以及给 objectui#3226 的关键警示(conversion 只覆盖走 ObjectStack loader/存量行的路径,不覆盖直喂 SchemaRenderer 的 consumer SDUI 文档 —— objectui 分片在删 ?? 前必须先回答仓外消费者属于哪一类)。第 4 笔已在本单评论区,objectui 分片按其 feat(security): ADR-0099 P1 — Layer 0 exemption reads the carried posture rung (#3211 M2) #3226 的 Blocked-by 流程会读到。

    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions