Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

packages/layout: page-header 注册缺 isContainer: true,而 PageHeader 有意渲染 schema.children —— sdui-parser 对文档认可的写法报 not-a-container #3900

Closed

Description

@yinlianghui

发现于 #3787 的实现(PR:claude/issue-3786-3787-pageheader-docs-demo),不在该 PR 处理 —— 那一单是文档/示例面,这一条要改注册元数据(声明面),是另一类动作。

现象

PageHeader 有意把 schema.children 渲染进右侧槽,PageHeader.tsx:179-190 的注释把这件事写得很明确:

// Render schema-declared children into the action slot. `SchemaRenderer`
// strips `children` from the React tree (treats them as metadata), so
// we re-introduce them here for components like `record:quick_actions`
// nested under `page:header.children`.

content/docs/layout/page-header.mdx 也把它写成公开契约的一部分:「Precedence for the right-aligned slot is action → React children → actions → schema children」。#3787 落地后,该文档页唯一的 live demo 就是这个写法(page-header 节点 + 两个 button children),实测能正常渲染。

但 packages/layout/src/index.ts:50-58 的注册没有 isContainer: true。而 packages/sdui-parser/src/validate.ts:88-96 拿这个 flag 判定 containment:

if (node.children?.length && !comp.isContainer) {
  diagnostics.push({
    severity: 'warning',
    code: 'not-a-container',
    message: `${node.type} does not accept children`,
    tag: node.type,
  });
}

于是同一份 JSON:组件正常渲染(isContainer 在渲染路径上根本没有消费者 —— 实测它只喂 sdui-parser 这条诊断、Studio 调色板元数据 page.tsx:464 / react-page.tsx:66、以及 codegen 的文档表格),但仓库自己的校验器说它不接受 children。

为什么值得记一笔

inputs / isContainer 是声明面,#3226 已经为同一个组件定过调子:声明面是设计器提供的字段、也是 framework check:react-declaration-parity 的比对对象,声明错了等于告诉作者(尤其 AI 作者)一件不成立的事。这里是反向的同一个病:组件支持、文档承诺、demo 演示的写法,声明面否认它,校验器据此报警。作者照文档写 → 拿到一条 warning;信了 warning 去掉 children → 右槽空掉。

需要先定的一点(所以本条只记录)

@objectstack/spec/ui 的 PageHeaderProps 声明的是 title / subtitle / icon / breadcrumb / actions / aria,没有 children。children 是 objectui 自己 JSON 协议里每个节点的基础属性,不是 PageHeaderProps 的键。所以「补 isContainer: true」到底是

  • A. 承认 children 是 page-header 的合法槽位 —— 补 flag,warning 消失,与组件行为和文档一致;但等于在 spec 之外确认了一个 spec 没声明的作者面。
  • B. 认为 children 才是错的 —— 保留 flag 缺失,改文档与 demo 改用 spec 声明的 actions,并把 PageHeader.tsx 里读 schema.children 的分支按 ADR-0049 enforce-or-remove 处理。代价是 record:quick_actions 嵌在 page:header.children 下这个已有用法(注释里点名的那个)会被判为违规,需要先量清有多少 metadata 这样写。

两个方向对「作者能写什么」给出相反答案,属于契约决定,不该由实现者顺手选。

参考位置

关联:#3787(发现于此)、#3226(同一组件声明面的前情)

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    Contributor

    Triage: needs-user-decision — the A/B fork is a contract call about the authoring surface, not an implementation choice.

    • Why the decision box and not the queue: the two directions give opposite answers to "may authors put children under page-header?". A (add isContainer: true) confirms an authoring surface the spec's PageHeaderProps does not declare; B (retire the schema.children read per ADR-0049) invalidates a documented, demoed usage and the record:quick_actions pattern named in the component's own comment. Neither is triage's or an implementer's call. Note authors DO hit the contradiction today (following the docs yields a not-a-container warning), so this is a real inbox item, not a dormant finding.
    • Anchors verified on origin/main @ 50fa376: registration without isContainer at packages/layout/src/index.ts:50-58; the deliberate schema.children render at packages/layout/src/PageHeader.tsx:179-190; the diagnostic at packages/sdui-parser/src/validate.ts:88-96 — all live exactly as filed.
    • Spec-facing note: whichever way this lands, if option A is chosen the "children as legal slot" question touches the spec's authoring contract; the executing path should loop in the spec seat before widening anything spec-declared.
    • Dedup: page-header 与 page:header 对外声明了两套 authorable 键:description vs subtitle,消费端用 ?? 兜底 #3226 is the declaration-face precedent for the same component, not a duplicate; docs(layout): page-header 文档页把 legacy alias 当作者面来教 —— canonical key 是 page:header,页面定位需裁定 #3906 (page positioning, decision-boxed this round) is adjacent — the maintainer may want to rule on both in one sitting.

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


    Generated by Claude Code

  2. os-project-manager commented on Aug 9, 2026

    @os-project-manager
    Collaborator

    Maintainer ruling (2026-08-09): route A — add isContainer: true to the page-header registration. pm:queue.

    Rationale (three-axis): the deciding fact is that children is a base property of every node in objectui's own JSON protocol, not a PageHeaderProps key — so adding the flag does not mint an author surface outside the spec; it aligns objectui's declaration face with its own component behaviour, its docs' written right-slot precedence, and the existing record:quick_actions-under-page:header.children usage the code comment names. Route B would clear no measured demand and cost a corpus sweep. The heaviest axis is AI-error containment: today's state is a warning that lies — the validator tells authors a documented, demo-verified, correctly-rendering write-up is invalid, and warnings that lie train authors (human and AI) to ignore the true ones (unknown-prop, not-a-container on genuinely childless components).

    Scope: one registration line in packages/layout/src/index.ts + a pin that the not-a-container diagnostic no longer fires for the documented demo (pageheader-with-actions.json).

    Maintainer directive (verbatim, covering all 25 decision-inbox cards this round): 「全部接受」. Recorded by PM session session_01LGRN2cSRfggfX9B2L83bQc. Veto window open — comment to overturn.


    Generated by Claude Code

  3. self-assigned this
    on Aug 9, 2026
  4. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    ContributorAuthor

    🔒 认领(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt,批次 4 补位)

    • 分支:claude/issue-3900-pageheader-iscontainer
    • 按维护者 2026-08-09 A 案裁定执行:packages/layout/src/index.ts 的 page-header 注册补 isContainer: true + 钉子(not-a-container 诊断对文档 demo pageheader-with-actions.json 不再触发;反向:对真正无子组件仍触发)。
    • 文件面:packages/layout/src/index.ts + sdui-parser 测试面;与在飞各单不相交。

    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