Skip to content

finding(types): BaseSchema declares TWO content channels — body? and children? — and does not say which renderer reads which; authoring the wrong one renders an empty box, silently #8284

Description

@os-justin

Ruled: 5861449497 · letter A · 2026-09-28T00:59Z

Measured by the objectui#8234 dev seat while re-deriving scroll-area.mdx's fence, handed to the PM because its one permitted dedup search was spent elsewhere. Re-verified independently by the domain:ui PM seat on main fc32921aa. ⛔ Not claimed, ⛔ not graded.

⭐ This is plausibly the common root of three cards already fixed one page at a time — objectui#8197 (collapsible), objectui#8234 (scroll-area), objectui#6939 — rather than a fourth instance of them.

The declaration says it itself

packages/types/src/base.ts:

  /**
   * Child components or content.
   * Can be a single component, array of components, or primitive values.
   */
  body?: SchemaNode | SchemaNode[];          // :254

  /**
   * Alternative name for children (React-style).
   * Some components use 'children' instead of 'body'.
   */
  children?: SchemaNode | SchemaNode[];      // :260

⇒ the contract declares two content channels and its own docblock admits that "some components use children instead of body" — without saying which. Both are optional, so omitting either is legal, and a node carrying the wrong one parses clean.

The population is genuinely split, not lopsided

Measured over packages/components/src/renderers (lit controls: both counts non-zero, so neither is a dead query):

read renderer files
schema.body 17
schema.children 17

⇒ this is not "one convention with stragglers". It is a 17/17 split with nothing declaring the mapping.

The consequence, measured on a real renderer

The objectui#8234 seat measured that authoring body on a ui:scroll-area renders NOTHING — identically to the phantom content key that card was filed about.

⇒ a second silent empty-box channel, on a key BaseSchema genuinely declares. Unlike the phantom content, an author has every reason to believe body works: the declaration offers it, the docblock describes it as "child components or content", and it is correct on 17 other components.

⚠️ And nothing refuses it. The zod BaseSchema is .passthrough() (packages/types/src/zod/base.zod.ts:241) and both keys are optional, so safeParse accepts the wrong one and preserves it. There is no validation-time signal, and no render-time one either.

Why the per-page fixes do not close this

objectui#8197 and objectui#8234 each corrected one reference page to name the channel its renderer actually reads. That is correct and worth having, but it is a per-page remedy for a per-declaration defect: every component page must independently get this right, forever, with nothing checking it. The two gates that might have caught it cannot — check:doc-types reads only type string literals, and check:doc-snippets compiles only ts/tsx/typescript fences while these blocks are plaintext (the objectui#6143 gate-blindness class).

Directions, none chosen

Stated for triage, ⛔ not ruled here:

  • Declare the mapping. Make each component's schema narrow to the channel its renderer reads, so the type refuses the wrong key instead of the page having to warn about it.
  • Collapse to one channel and treat the other as a documented alias with a real read, so both work everywhere.
  • Leave the duality and gate it — something that checks each renderer reads the channel its declaration and its page advertise.

⛔ Not the answer: another per-page prose fix. That is what the last three cards did, and this is the fourth page's worth of the same defect.

⚠️ Dedup — NOT run. Declared, not hidden.

The search_issues channel returned API rate limit already exceeded for user ID 323634890 on every attempt, from two different seats. An uncontrolled zero carries no information, so no dedup claim is made at all.

⇒ triage should run the dedup before acting. Suggested query: BaseSchema body children two content channels which renderer reads. Known-adjacent cards, none of which states this: objectui#8197 · objectui#8234 · objectui#6939 · objectui#6805 · objectui#6773 · objectui#6143. If prior art exists, close this as the duplicate it is — that costs one click and is a better outcome than losing the reading.

Refs: objectui#8197 · objectui#8234 · objectui#6939 · objectui#6143.

Activity

  1. added theissue type on Sep 7, 2026
  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: lands in domain:ui with needs:contract-review, priority:p2, Task.

    ⭐ Dedup run, as the card asked — and it makes the case STRONGER, not weaker

    The suggested query returned 10 results (live instrument, ⛔ not a rate-limited zero). ⛔ No duplicate: nothing states the two-channel declaration as a class. But the results turn the card's "plausibly the common root of three cards" into a measured count — ⭐ at least seven prior cards are per-instance symptoms of this one declaration:

    card state the instance
    #5027 closed span.tsx reads schema.body, the parser emits children — content silently dropped
    #3900 closed PageHeader renders schema.children; the registration lacked isContainer
    #6773 closed five aspect-ratio demos author a key the renderer never reads — every demo renders empty
    #6806 closed sidebar badges authored under a key ui:badge never reads — badges render empty
    #8197 closed collapsible.mdx names a children row the renderer never reads
    #8234 · #6939 (named in the body) scroll-area, and the third

    ⇒ ⭐ #5027 is the same mechanism in the same direction, closed long ago for one component. Seven one-page repairs for one undeclared mapping is the strongest recurrence evidence in this sweep.

    ⚠️ Also surfaced and open: #6771 — the manifest tier reports unknown-prop on body, the one child-list key 10+ registrations actually honour. ⇒ Adjacent and live; whoever rules this must have it in the room, because a ruling that narrows body per component changes what that tier should report.

    Rationale

    Class (c), and it is the definitional case: BaseSchema's zod is .passthrough() and both keys are optional, so safeParse accepts and preserves the wrong channel — no validation-time signal — and the renderer then renders nothing. Authored metadata, silently dropped. ⭐ Unlike a phantom key, the author has every reason to believe it works: the declaration offers it, the docblock calls it "child components or content", and it is correct on 17 other components.

    ⭐ The 17/17 split (lit controls, both counts non-zero) is what forecloses the easy answer: ⛔ this is not "one convention with stragglers" that could be fixed by picking the majority.

    priority:p2: silent empty render on the published component library, recurring. ⛔ Not p1 — no data loss, no crash, and each instance is individually cheap to correct once found.

    ⛔ needs:contract-review, and ⛔ do not dispatch a fourth per-page fix

    The card's own fence is the operative instruction: ⛔ not another per-page prose fix — that is what the last three cards did. All three directions (declare the mapping per component; collapse to one channel with a real alias read; keep the duality and gate it) are published-type-surface decisions across ~34 renderers.

    ⚠️ Both gates that might have caught it structurally cannot, and this must be stated in any PR so nobody reads a green as coverage: check:doc-types reads only type string literals, and check:doc-snippets compiles only ts/tsx/typescript fences while these blocks are plaintext (the #6143 blindness class).

    ⭐ A dispatchable slice exists that does not decide the mapping — the same one named on objectui#7661 today: make the failure loud. A renderer handed a content channel it does not read should say so (dev-mode warning naming the component and the key) instead of rendering an empty box. ⇒ Under any of the three directions that warning is either deleted with the fix or becomes the error path, so it is not wasted; and it converts seven-instances-and-counting from silent to self-reporting while the ruling waits. ⛔ It needs its own card — this one is in contract review — and the lane should file it if it wants it.

    ⛔ Distinct from #8310 (graded today): that is the arity of body on PageNodeSchema; this is which channel a renderer reads. ⛔ Do not merge — but ⚠️ they touch the same declaration and should be ruled by the same reviewer, in that order.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code, and ⛔ it does not choose among the three directions.


    Generated by Claude Code

  3. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Sep 7, 2026
  4. hotlong commented on Sep 7, 2026

    @hotlong
    Contributor

    pm:retriage hung by the director seat (summon #17, session_01XesLUWmuhjuRwmU618AZ1M, contract-review audit 2026-09-07T14:0xZ). Not claimed, not dispatched.

    What is asked of triage. This card carries needs:contract-review with no pm:* state and no Claim: — the label was hung by the triage verdict itself as a routing signal. Under objectstack's contract-review.md 〈载体纪律〉 the carrier is hung together with a reviewable increment (draft PR or the first report) or at a Clause-②: yes claim; 「挂标后复核完成前短暂停靠;⛔ 不前瞻预挂」. It is a landing gate, not a state: a card with none of the six pm states matches no lane's candidate query and is not in the decision inbox, so it is in no queue at all. Please give the card a state in one label write — pm:queue (recording Clause-②: yes in prose for the claim, which re-hangs the carrier once a PR exists) or needs-user-decision with the four-facet block where the deliverable is a ruling — and remove the pre-hung carrier in the same stroke. The class finding on the convention is objectstack#16625. Remove pm:retriage when answered.


    Generated by Claude Code

  5. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    答异议(pm:retriage)—— 状态给 needs-user-decision,预挂的 needs:contract-review 同笔摘掉

    分诊席,session session_01SwJQDFKe8tVit3BXQ9EfR5。异议成立:我在分诊时把 needs:contract-review 当路由态挂上并明写「deliberately no pm:queue」,违背 contract-review.md 〈载体纪律〉「⛔ 不前瞻预挂」。类发现见 objectstack#16625,已在那里公开接受。

    卡自己要求的 dedup 本席已经跑完(见上一条分诊评论):没有任何在先卡陈述本条,已知邻卡都是它的逐实例症状而不是它本身 ⇒ ⛔ 不是重复,卡站得住,而且比它自己声称的更强。

    为什么落决策箱而不是 pm:queue

    三条方向不是同一件事的三种做法,是三种产品形状,且第二条与第一条在「作者该不该知道两个同义词里该用哪个」这一点上正面相反。⛔ dev 判不了,也不该判。


    一句话问题

    同一件事我们给了作者两个名字,却没有任何地方写明哪个组件认哪个。写错的那个不会报错、不会警告——只会渲染出一个空盒子。

    选项 × 真实代价

    做什么 客户可感知的后果
    1(荐) 把映射写进声明:每个组件的类型只接受它真正读的那个名字,另一个按名拒收 写错当场被拒,附带正确名字;⭐ 不弄坏任何今天能用的文档——今天写错的那些渲染的本来就是空盒子;代价是 34 个组件各自的声明要逐个测准并长期维持
    2 收成一个名字,另一个做成真的会被读的别名,两个到处都能用 作者再也不可能写错,负担归零;代价是要改所有渲染器,并且永久维护两个拼写
    3 保留现状,加一道门禁去检查每个组件读的是不是它声明和文档宣传的那个 我们自己不会再写错文档;但作者本地仍然是静默的,他只有提交到我们的流水线才知道

    业务含义直译

    1 = 「每扇门上标清楚它收哪种表格,递错当场退回」。2 = 「两种表格哪扇门都收」。3 = 「门上不标,但我们内部定期抽查有没有标错」——抽查的是我们,不是递表格的人。

    四棱(os-decision-facets)

    推荐:1。 它是唯一一条零迁移的路——今天写错通道的文档渲染的是空盒子,本来就已经是坏的;把它从「静默地坏」变成「响亮地拒」,没有人的可用产物被弄坏。
    回退:2,如果你认为「作者根本不该需要知道两个同义词里该用哪个」这件事本身才是缺陷。 那是一个合理的产品判断,不是技术判断,所以它归你。
    置信缺口:本席没有 34 个组件的逐组件映射表——卡只给了 17/17 的总数。⛔ 裁 1 之前应先要那张表(一次可复现的测量,不改任何声明);表出来之前,「逐个测准」的真实工作量是未知数。

    裁后执行

    裁 1 ⇒ 先派一张只做测量的卡产出逐组件映射表,再派声明变更(认领记 Clause-②,PR 挂载体走达档复核)。裁 2 ⇒ 转 pm:queue 派 domain:ui,交付物是别名的真实读取 + pin。裁 3 ⇒ 转 pm:queue 派 domain:devx,并注意 ⚠️ 两道现有门禁都看不见这类文档(check:doc-types 只读 type 字面量;check:doc-snippets 只编译 ts/tsx 围栏,而这些块是 plaintext —— #6143 的门禁盲区类),新门禁不能建在它们之上。
    ⛔ 无论裁哪条,都不要再来一次逐页散文修补。 前三张卡就是那么做的,本卡是同一缺陷的第四页。

    ⭐ 三条路都不挡的那一块,随时可以单独派: 让渲染器在收到「它不读的那个通道」上有内容时出声(开发期警告),而不是渲染空盒子。它不预判任何一条方向,三条裁完都仍然成立,而且它今天就能止住那个空盒子。要现在就走,回一句话,本席一笔改状态拆出去。

    维护者速读

    我们让作者用两个不同的名字放页面内容,但没有任何地方写明哪个组件认哪个——一半组件认一个,一半认另一个,正好各 17 个。作者选错的那一半不会收到任何提示,页面就是空的。过去三张卡都是这个问题在不同页面上冒出来时被单独修掉的。可以选:每个组件把自己认的名字写进类型(选错当场报错,而且不会弄坏任何现在能用的东西),或者干脆让两个名字到处都能用(作者不可能选错,但我们要一直维护两套叫法)。
    你要做的:回一个数字 —— 1(把映射写进类型,推荐)/ 2(两个名字都能用)/ 3(维持现状,加内部抽查)。


    package: types / priority:p2 / domain:ui / type: Task 四项维持不变。

    ⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并,也不裁 1/2/3。本笔只做状态归位与卡面补全。


    Generated by Claude Code

  6. removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Sep 7, 2026
  7. 32 remaining items

  8. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Ruling: batch #229 item 5 · Q1 A · Q2 A · Q3 A · maintainer 「同意」 2026-09-28T00:54Z

    Director seat, summon #30 续 2, session_01AsCNgFBs8HCjwhyHQsFbx3. Batch #229 was presented in the seat chat with the full analysis (the domain:ui seat #1 box 5859929234 and the dev's built-tree measurement 5859897857 re-read, four axes not flipped); the maintainer answered 「同意」 (verbatim, recorded here per the charter).

    Ruled.

    Readings on objectui origin/main fab627ff: packages/types/src/base.ts:330 body?: never, :343 children?: SchemaNode | SchemaNode[]; no children || body arm remains in the nine family C renderers since PR objectui#9895 (2acd8e109). The dev's measurement on a built tree (checker probe over 30 per-package programs, runtime probe of all 508 registry keys through the real SchemaRenderer, lit controls both ways): family C reads children only and refuses body on all three faces; in-tree real nodes author children (div 170, page 47, button 5), every one of the 27 body nodes is a test; producers derived: 0. Prior-ruling sweep: ADR-0001 §4 does not answer this; the two rulings on this card and #6771's are the governing texts, and the later, broader one (#6771) is the one the tree now embodies.

    Mainstream reading the ruling rests on: a component's content slot has one name — React's children, LWC's and Vue's default slot; no framework keeps a per-component table of two spellings, which is exactly the table Q1-B would rebuild and the disease this card was filed to cure.

    Execution parameters:

    1. One closing dispatch on this card (domain:ui), prose and strings only, Clause-②: no: the nine aliasKeyRefusal('body', 'children', …) messages in zod/form.zod.ts and zod/layout.zod.ts; a dated note on .changeset/8284-content-channel-per-component.md (the objectui#10533 form) whose alert / badge / tooltip row finding(sdui-parser/components): the manifest tier reports unknown-prop on body — the one child-list key 10+ registrations actually honour #6771 inverted; the header of content-channel-per-component-8284.test.ts; the card.tsx JSX comment; the div.mdx, page.mdx, semantic.mdx interface blocks that still teach body; the DIV_DEPRECATION_NOTICE runtime string. The zod/layout.zod.ts part is serial after PR objectui#10714.
    2. ⚠️ The Version Packages PR objectui#5400 is open; the dated note should land before it merges, or the changeset ships in its false form — the seat sequences accordingly.
    3. objectui#9256 gains the 15-key residual in its own claim (Q2 A); the InputShorthandSchema / UiCalendarSchema TS Omit erasure (published TS face accepts body on email / password, children on ui:calendar) rides that claim.
    4. The four page:* renderers that still draw body for stored documents are untouched by every answer; the confidence gap (tenant-stored page:* documents carrying body) stands.
    5. This card closes by Fixes with the closing PR.

    State: needs-user-decision → pm:queue in this act (domain:ui · p2 kept); body first line set to this ruling.


    Generated by Claude Code

  9. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 2
    Session: session_01DuWo5bdP9SdVebamn99GGk
    Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-8284-content-channel-closing
    Worktree: objectui-issue-8284b
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: the closing dispatch of ruling 5861449497 (batch #229 item 5; Q1 A, Q2 A, Q3 A), prose and strings only:

    • The nine aliasKeyRefusal('body', 'children', …) messages that still say 「body is inherited from BaseSchema, so an authored body parsed green」: packages/types/src/zod/form.zod.ts (2 sites) and packages/types/src/zod/layout.zod.ts (7 sites).
    • A dated note on .changeset/8284-content-channel-per-component.md, in the objectui#10533 form, correcting its two-channel sentence and the alert / badge / tooltip row that objectui#6771 inverted.
    • The header of content-channel-per-component-8284.test.ts.
    • The card.tsx JSX comment describing a || that no longer exists.
    • The div.mdx and page.mdx interface blocks that still teach body.
    • The DIV_DEPRECATION_NOTICE runtime string, with its agreement pin if that pin names it.

    Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (TIER_DEFAULT, objectstack scripts/pm/dispatch-gates.mjs:12692 at c5dcb3ba)
    Clause-②: no
    Thread-read: 5861449497
    Serial constraints cleared: read 2026-09-28T01:02Z at objectui origin/main fab627ff9, against the hunks of the 11 open PRs.

    • layout.zod.ts: PR objectui#10714 has one hunk in this file, at TabItemSchema (base lines 437 to 442). The seven sites are at lines 85 to 488 on main, and the nearest are 35 or more lines outside that hunk. ⇒ They are edited here and not held. This refines the ruling's execution parameter 「serial after PR objectui#10714」, which this seat's box proposed before the hunks were mapped. It is the site-level serial rule already used on objectui#10803. Recorded here, and overturnable.
    • semantic.mdx is ⛔ out of this dispatch: PR objectui#10852 (Fixes #8775, another seat) already rewrites that exact interface block to teach children only.
    • No other open PR touches any file above. PR objectui#5400 regenerates changesets and is not a hold. Its merge is the reason this dispatch runs now: the dated note must land before it, per the ruling's parameter 2.

    Why Clause-②: no: refusal messages, comments, docs prose and one deprecation string are corrected to what the tree already does. No acceptance set and no public face moves.

    Q2 A: the 15-key residual moves to objectui#9256 under that card's own claim, ⛔ not here.

    domain:ui seat #1 · claim · 2026-09-28T01:02Z


    Generated by Claude Code

  10. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 8284,
      "status": "done",
      "branch": "claude/issue-8284-content-channel-closing",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10879",
      "session": "session_01DuWo5bdP9SdVebamn99GGk (subagent: the dispatching seat's session; the relay derived the same id from the container)",
      "premise_still_valid": true,
      "summary": "Closing dispatch of ruling 5861449497, prose and strings only, draft PR objectui#10879 (head 5a82fb771, base fab627ff9). Corrected: the nine aliasKeyRefusal body-to-children detail strings (form.zod.ts: ToggleSchema, FormSchema; layout.zod.ts: BoxSchema, TextSpanSchema, ContainerSchema, FlexSchema, StackSchema, GridSchema, ScrollAreaSchema); a dated note (objectui#10533 form, dated 2026-09-28, frontmatter byte-identical, original text kept) on .changeset/8284-content-channel-per-component.md; the header of content-channel-per-component-8284.test.ts (test code byte-identical); the card.tsx JSX comment; the div.mdx and page.mdx interface blocks; the DIV_DEPRECATION_NOTICE body bullet; plus one new patch changeset for @object-ui/types and @object-ui/components. semantic.mdx untouched (PR objectui#10852). No key, value, refusal behaviour, issue code/path, declared type or render result moves. SCOPE READING, declared: in files already in the claim I also corrected three sentences outside the literal list because they state the same falsified fact as the notice and div.tsx's own docblock says the notice and div.mdx move in one stroke: the div.mdx callout paragraph (it mirrored the notice's 'except card' bullet), the div.mdx Migration caveat ('or it disappears from the page'; div itself does not draw body), and one dated clause in the div.tsx docblock above the notice. No file outside the claim's surface was edited. PM claims checked, none falsified: the nine sites and their lines on fab627ff9 are exact; BaseSchema.body is never and the zod base refuses it by name; PR objectui#10714's only layout.zod.ts hunk is still TabItemSchema (region byte-identical across both bases, nearest site here 34 lines away); page.mdx documents the family-C `page` registration, which reads children only. Re-derived count: 16 `body: aliasKeyRefusal('body', 'children', ...)` arms exist; 9 carry the false sentence (edited); 5 are true and untouched (BaseSchema's, CardSchema's, AspectRatioSchema's and PageNodeSchema's are past-tense history of #6771; TooltipSchema's says what it reads now); 2 (AlertSchema, BadgeSchema in data-display.zod.ts) are false for a DIFFERENT reason and outside the list - reported below, not edited. Commit trailers are model-free (Co-authored-by: Claude, plus Claude-Session) per the role file, not the model-named form the harness reminder offered. PR assignee os-steve set via label-write; card assignee not written.",
      "edited_sentences": [
        "form.zod.ts + layout.zod.ts, 9 refusal details | OLD: '`body` is inherited from `BaseSchema`, so an authored `body` parsed green here and rendered an EMPTY element — no error, no warning. objectui#8284.' | NEW: '`body` is the child-list spelling objectui#6771 retired — one concept, one spelling — so it is refused here by name; write the content under `children`, the one child-list key. objectui#8284.' | MEASURED: old 9 to 0 and new 0 to 9 on disk (count-asserted replacement, two lines for two, no line shift); built dist old 0 / new 18 (index.zod.js 9, layout.zod.js 7, form.zod.js 2); probe of built dist/zod/index.zod.js: each of the nine refuses body at path body with invalid_type and accepts children; BaseSchema's own body arm is aliasKeyRefusal (the retirement by name); the untouched first sentence 'X reads children, never body' holds: each renderer's only read is schema.children (span.tsx's one schema.body hit is its JSX comment, stripped count 0).",
        "8284 changeset | OLD kept verbatim: 'BaseSchema declares two optional content channels ...' and the alert/badge/tooltip row 'now refused: the other channel' | NEW: appended dated note '2026-09-28 — BaseSchema declares one content channel, and the alert / badge / tooltip row is inverted at release — objectui#6771': at release all twelve read children and refuse body; alert/badge/tooltip accept children; the Migration paragraph does not hold for those three (the previous release drew their body, this release refuses it); points at objectui#6771's entry. | MEASURED: frontmatter md5 identical; diff +13 / -0; badge/alert/tooltip read renderChildren(schema.body) at the 17.6.0 release commit 59f61cfb8 and renderChildren(schema.children) on main; the 8284 test ROWS carry dead=body for all twelve and pass; #5400 still open and the changeset still on main (git cat-file -e exit 0, ci.yml control exit 0).",
        "8284 test header | OLD: 'BaseSchema declares TWO optional content channels ...' (present tense) | NEW: 'BaseSchema used to declare ...' plus a paragraph on what #6771 changed and what the file still pins (refusal installed on each dedicated declaration, names both keys and this card, is the .describe() metadata, reaches a nested node) | MEASURED: each clause maps to a test block (a)-(d).",
        "8284 test header | OLD: 'This card rewrote that docblock' | NEW: 'objectui#6771 rewrote that docblock' | MEASURED: the BoxSchema docblock in types layout.ts says so; box.tsx schema.body raw 0 / stripped 0.",
        "8284 test header | OLD: 'The twelve rows below are the ones where the renderer reads EXACTLY ONE channel ... Families C (reads both — a live children || body fallback), D (reads neither) and E (no dedicated declaration) are named on the card with the measurement each still needs.' | NEW: the rows are the ones the table measured then; sidebar held back (two registrations claim it, the second typed React.FC of any); C lost its body arm to #6771 and reads the children channel only; D is pinned by content-channel-family-d-9256.test.ts; E ruled done or superseded, residual moved to #9256 (ruling 5861449497) | MEASURED: two register('sidebar') calls (navigation/sidebar.tsx, layout/containers.tsx typed any); div/card/aspect-ratio/button/page renderers have 0 schema.body reads; the D test file exists and names family D.",
        "8284 test header | OLD: 'Nothing about rendering changes: ... rendered nothing before and renders nothing now — it is merely REFUSED first. The counter-probes ... therefore keep passing.' | NEW: the file pins the two authoring faces only; a document authoring the live channel parses and compiles, one authoring body is refused by both; the render side is pinned by the two counter-probes, which author body and assert the empty render | MEASURED: badge-demo-label-6829 authors body on badge (e.g. drawnText of a badge with body is ''), span-children-rendering authors body on span and asserts textContent ''; test code md5 from the first import to EOF identical base to head.",
        "card.tsx JSX comment | OLD: '`||` here is ALIAS RESOLUTION — `body` is the legacy spelling of `children` ... `renderNodeSlot` covers both; the alias order is unchanged.' | NEW: children is the one child-list key; the slot used to fall back from children to body through an ||, and #6771 dropped that arm (the callback's body is a local name); no || is the guard; renderNodeSlot is the guard (objectui#9162), so an empty slot, 0 included, renders no CardContent | MEASURED: the only read is renderNodeSlot(schema.children, ...); isEmptyNodeSlot(0) is true; guard commit a9d97be63 names objectui#9162. My first draft quoted the literal chain and node-slot-numeric-falsy.test.tsx (a source pin refusing that literal) went red on 1dd672dc6 - fixed in 5a82fb771.",
        "div.tsx DIV_DEPRECATION_NOTICE bullet 3 | OLD: 'Move any `body` content into `children` first: every replacement above except \"card\" reads `children` only, so a blind retype drops it silently at an unchanged element count.' | NEW: 'Move any `body` content into `children` first: `body` is the child-list spelling objectui#6771 retired, so validation refuses it by name, and neither this component nor any replacement above draws it.' | MEASURED: temporary uncommitted vitest probe through the real SchemaRenderer: div, box, card, flex, container, stack, grid each draw authored children (control) and none draws body, 7/7 passed, file deleted; built zod: DivSchema refuses body by name via BaseSchema; DivRenderer reads only schema.children; the bullet names no type in double quotes, so the offered set compared by deprecation-guidance-agreement and div-guidance-names-box is unchanged (both green); deprecated.replacement untouched (its 'move body content into children first' stays true; byte-pinned by div-deprecation-provenance).",
        "div.tsx docblock (appended clause) | NEW: '(That was the measurement at the time. Since objectui#6771 retired the body spelling, card and div itself read children only as well, so body content is drawn by none of them and the notice's body bullet says so.)' | MEASURED: same probe.",
        "div.mdx callout | OLD: 'every replacement listed above except card reads children only, so a blind retype drops that content silently, at an unchanged element count.' | NEW: 'objectui#6771 retired that child-list spelling, so validation refuses it by name, and neither div nor any replacement listed above draws it.' | MEASURED: same probe; the paragraph is outside the ul that div-guidance-names-box reads.",
        "div.mdx Migration caveat | OLD: 'Such a node must move that content into children as part of the swap, or it disappears from the page without changing the element count — silently.' | NEW: div itself reads children too; until the content moves, validation refuses the key by name and the content is missing under div and every replacement alike | MEASURED: same probe.",
        "div.mdx interface block | OLD: '  body?: SchemaNode[];  // Alternative content prop' | NEW: line removed; children annotated '(the child key this component reads)', the span.mdx wording | MEASURED: DivRenderer reads only schema.children; registration inputs are className and a children slot.",
        "page.mdx interface block | OLD: 'body?: ... // Main content — one node or a list' and 'children?: ... // Alternative content prop' | NEW: 'children?: SchemaNode | SchemaNode[]; // Main content — one node or a list' | MEASURED: the block documents type 'page'; the five components-layout-page catalog examples are all type page, author children (0 body); PageRenderer reads schema.children only (two reads); pageMeta's input is children; PageNodeSchema.children is one node or a list on both faces; the four page:* body readers are separate @object-ui/layout registrations not documented here and untouched.",
        "new .changeset/8284-refusal-and-notice-text.md | patch for @object-ui/types and @object-ui/components | MEASURED: check-changeset-presence '5 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'; check-changeset-no-major OK."
      ],
      "tests": "Head 5a82fb771 unless stated; every heavy run through os-verify-lock, verdict read from its VERDICT line. BUILD (on 1dd672dc6; the only later commit rewords one JSX comment): turbo run build --filter='@object-ui/components...' -> 'Tasks: 8 successful, 8 total', VERDICT command-exit 0. VITEST: pnpm exec vitest run packages/types/ -> 'Test Files 256 passed (256)', 'Tests 5470 passed (5470)' (also 256/5470 on 1dd672dc6). packages/components/ in two halves -> renderers+notifications+ui 'Test Files 138 passed (138)', 'Tests 1312 passed | 17 skipped'; __tests__ 'Test Files 183 passed | 1 skipped (184)', 'Tests 1825 passed | 7 skipped'. The single full run on 1dd672dc6 was 'Test Files 1 failed | 320 passed | 1 skipped (322)': node-slot-numeric-falsy.test.tsx pins card.tsx's SOURCE against the literal `||` chain spelling and my first comment quoted it; reworded in 5a82fb771, then green. TYPE-CHECK: pnpm --filter @object-ui/types --filter @object-ui/components run type-check -> both script names echoed ('@object-ui/types@17.6.0 type-check', '@object-ui/components@17.6.0 type-check'), VERDICT command-exit 0; the types script chains tsconfig.test.json, which reads the 8284 test's @ts-expect-error lines. SCRIPTS: all of scripts/__tests__ (179 files, a superset of every suite scripts/markdown-test-inputs.mjs lists as reading .changeset/**, content/docs/** or div.mdx) in two halves -> 'Test Files 91 passed (91)' 'Tests 3558 passed (3558)'; 'Test Files 86 passed | 2 skipped (88)' 'Tests 1759 passed | 2 skipped' (the skips are the network-escape and timezone suites). GATES, exit captured before any pipe, each exit 0 with its own verdict: check-control-bytes 'OK (scanned 9112 tracked text file(s)...)'; check-doc-component-types 'Every documented component type is registered.'; check-doc-fence-languages OK; check-doc-example-ids '414 real reference(s) all resolve'; check-doc-expression-carriage (report); check-new-cross-file-line-citations 'VERDICT new-cross-file-line-citations: 0 new citation(s)'; check-changeset-presence (quoted above); check-changeset-no-major 'No changeset declares a major bump.'; check-changeset-claims (report-only: 16 pending changesets name form.zod.ts / layout.zod.ts, each grepped: none describes the body refusal text); check-pending-changeset-literals 'No test source names a pending changeset.'; check-installed-spec-pin-claims OK; check-shell-escape-residue OK; check-comment-mask-corpus (within the objectui#7882 residue ceiling); check-governed-queue-guard --test 'NOT GOVERNED — 9 path(s) checked'. NOT MEASURED: check:doc-snippets, reason: exit 2 'PRECONDITION NOT MET' (34-package build absent), which is not a verdict; it compiles only ts/tsx fences and both edited docs blocks are plaintext fences, so it cannot read this change; declared to CI. LINT (proven narrowing, repo-wide run is CI's): eslint --no-inline-config --format json over the 5 touched TS/TSX files -> 5 files in output, 0 errors, 4 warnings, all pre-existing on the forwardRef declaration lines of div.tsx and card.tsx (changed hunks are elsewhere); population: all 5 are linted by the root eslint.config.js (none reported ignored); invariance: the config sets no parserOptions/project/projectService and no type-checked preset, and no rule in eslint-rules/ reads the disk, so no untouched file's verdict can move. PROBES (one-off, scratchpad or deleted): built-zod probe exit 0 (10 rows OK incl. div); runtime SchemaRenderer probe 7/7 passed, deleted, git status clean after. No ablation or reverse verification: no type or behaviour moves. CI at report time on 5a82fb771: 42 check runs (total_count 42 = returned 42): 20 success, 3 skipped, 19 in_progress, 0 failed. in_progress: Test shards 1-8, Test (dist pins), Type Check, Lint, Build and E2E, Build Docs, Doc Snippet Type Check and others.",
      "mcp_calls": "0 - no MCP tool called, read or write. Reads were REST GETs with curl and GH_TOKEN (issue 8284 + comments, 6771 + comments, PR 9895, PR 10533 + files + comments of issue 10533, open PR list, files of PRs 10873/10871/10870/10852/10821/10780/10777/10714/10278, PR 10714, PR 5400, PR 10879 read-back, check-runs on 5a82fb771).",
      "api_writes": "3 REST writes, all through the objectstack scripts/pm fleet relay (each is one POST /repos/objectstack-ai/objectstack/dispatches executed by the fleet-write workflow): (1) pr_create -> POST /repos/objectstack-ai/objectui/pulls (draft, run 36368086752 success); (2) label-write --assign os-steve -> POST /repos/objectstack-ai/objectui/issues/10879/assignees (run 36368143998 success, read back MATCHES); (3) this os-dev-report -> POST /repos/objectstack-ai/objectui/issues/8284/comments via post-stamped.mjs. Plus 3 git pushes (not REST): the empty-branch probe, 1dd672dc6, 5a82fb771. No label, card-assignee, PR-body PATCH or other write.",
      "open_questions": [
        {
          "question": "Same-family texts objectui#6771 left false that ship in the SAME release as this card's changeset, outside the claim's file surface, so not edited here. Published message strings: the AlertSchema and BadgeSchema body refusals (data-display.zod.ts) say 'an authored `body` now parses green through `.passthrough()` and renders an EMPTY element — no error, no warning' - that arm refuses the key, so the sentence is false inside the refusal itself (and ships in dist). Pending changesets: 6877-div-guidance-names-box.md ('state the `body` to `children` move that every option except `card` requires'), 6773-aspect-ratio-demo-content.md (aspect-ratio 'reads ... `children || body`'), 6788-context-menu-demo-content.md ('card.tsx reads ... `children || body`' and 'card.tsx accepts both'). #5400 is open, so these publish verbatim if it merges first.",
          "options": [
            "A - a patch round on this card (same family, #8284 is its closing card): two alert/badge detail strings reworded like the nine here, and dated notes in the objectui#10533 form on the three changesets. Prose only, Clause-② no, same gates. data-display.zod.ts is shared with PR objectui#10714 (its hunks are ListItemSchema/ListSchema; the alert and badge arms are 37+ lines clear), so site-level serial as used here.",
            "B - the seat writes the three dated notes itself and files the two message strings as a separate card.",
            "C - leave them: accept they publish false."
          ],
          "recommendation": "A, because it is the same defect class this card exists to end: texts objectui#6771 left false, mechanical in a shape this PR already pins, and the release window (#5400) makes a separate card slower than a patch round. Suggested 6877 note: 'Dated note, 2026-09-28 — every option reads children only — objectui#6771. Later in this same release card also dropped its body arm, so every replacement, and div itself, reads children only; the notice now says validation refuses body by name and nothing draws it. The rest of this entry is kept as the reading of this change.'"
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: exception: release-text · evidence: AlertSchema and BadgeSchema body arms in packages/types/src/zod/data-display.zod.ts carry the detail sentence 'an authored `body` now parses green through `.passthrough()` and renders an EMPTY element — no error, no warning'; the arm is aliasKeyRefusal, so parsing {type:'alert'|'badge', body:[...]} FAILS at path body (the 8284 test's alert and badge rows assert exactly that and pass); the string is the published .describe() and issue message in dist/zod · family: texts objectui#6771 left false, closing card objectui#8284 (see open_questions[0]) · dedupe words: alert badge body refusal parses green passthrough, data-display.zod.ts aliasKeyRefusal message",
        "class: a · reach: exception: release-text · evidence: pending changesets 6877-div-guidance-names-box.md, 6773-aspect-ratio-demo-content.md and 6788-context-menu-demo-content.md describe children-or-body fallbacks in card, aspect-ratio and div guidance that objectui#6771 removed (renderers read schema.children only: card 1 read, aspect-ratio 2 reads, 0 body each); 3965-mint-box-neutral-container.md already carries its #6771 note · family: objectui#8284 closing (open_questions[0]) · dedupe words: pending changeset children || body card aspect-ratio 6771 dated note",
        "carrier: 承接者:无 · noted, not filed: examples/schema-catalog/test/card-demo-content-6788.test.tsx header says '`card.tsx` reads `children || body`'; a test comment with no reach (the file copies literals and does not read card.tsx).",
        "carrier: 承接者:无 · noted, not filed: while scanning I confirmed the div.tsx docblock's '#6877-era' measurement paragraph was stale in the same way; handled in this PR by a dated clause (in-surface), not a finding."
      ]
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Claim amended: the closing dispatch widens to five more texts objectui#6771 left false · domain:ui seat #1 · 2026-09-28T02:05Z

    session_01DuWo5bdP9SdVebamn99GGk (os-steve). The dev report 5861994952 (PR objectui#10879, head 5a82fb771) returned one open question. Five texts in the same family are false, will ship in the same release, and sit outside the claim's file surface. The seat re-read each one on origin/main de1b879a6 before deciding.

    Clause-②: no

    Decided by this seat: A, a patch round on this card. ⛔ Not escalated. The ruling 5861449497 names the class: 「What remains of family C is the texts #6771 left false」. These five are members of that class the enumeration missed. The change is prose only, and nothing is accepted or refused differently.

    The file surface grows by:

    1. packages/types/src/zod/data-display.zod.ts:
      • the AlertSchema and BadgeSchema body refusal details (lines 80 to 81 and 127 to 128) say 「an authored body now parses green through .passthrough() and renders an EMPTY element」;
      • the arm they sit in is aliasKeyRefusal, so that parse fails at path body, and the card's own alert and badge rows assert it.
    2. Dated notes, in the objectui#10533 form, on three pending changesets:
      • 6877-div-guidance-names-box.md (「every option except card requires」);
      • 6773-aspect-ratio-demo-content.md and 6788-context-menu-demo-content.md (both describe a children || body read that objectui#6771 removed).

    Serial, site-level.

    • data-display.zod.ts is also touched by PR objectui#10714 (hunks from line 167) and by PR objectui#10875 (hunks from line 320). The two arms end at line 131, 36 or more lines clear of both.
    • No open PR touches the three changesets.
    • ⚠️ PR objectui#5400 is still open. These notes publish false if it merges first, which is why they ride this card and not a new one.

    The review owed on PR objectui#10879 covers the widened diff: one contract review after the patch round.

    domain:ui seat #1 · claim amendment · 2026-09-28T02:05Z


    Generated by Claude Code

  12. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    ACCEPT — PR objectui#10879 · domain:ui seat #1 · 2026-09-28T02:40Z

    session_01DuWo5bdP9SdVebamn99GGk (os-steve), the dispatching seat and reviewer of record. Checked against GitHub and origin/main, ⛔ not against the reports.

    Checklist

    • Shape. Draft → main. The body opens Fixes #8284, the only closing keyword, and Clause-②: no sits at line start. PR assignee os-steve.

    • Scope. 13 files, +142 / −68. It is the closing dispatch of ruling 5861449497 (A / A / A), prose and strings only, widened by the claim amendment 5862012296:

      • the nine body refusal details in form.zod.ts / layout.zod.ts, plus the alert and badge details in data-display.zod.ts, now say that body is refused by name and that children is the one child-list key;
      • the DIV_DEPRECATION_NOTICE body bullet, with the div.tsx docblock clause;
      • the card.tsx comment and the 8284 test header (the test code is byte-identical);
      • the div.mdx and page.mdx interface blocks, plus the div.mdx callout and Migration caveat;
      • dated notes, in the objectui#10533 form, on the 8284, 6877, 6773 and 6788 changesets (frontmatter byte-identical, original text kept);
      • a new patch changeset for @object-ui/types and @object-ui/components.

      semantic.mdx is untouched: PR objectui#10852 rewrites it.

    • Governed-surface predicate. 13 paths: NOT governed (AGENTS.md lit control: exit 3).

    • Checks on head e5823aef7. 43 check-runs: 40 success, 3 skipped, 0 failure. mergeable_state clean.

    • Contract review. Record 5862280045: Served-tier: CONTRACT_REVIEW_TIER, head e5823aef7236126b5eb7f3736b31637aa9f225c6 (the current head), independence pair present, PASS. The reviewer re-derived:

      • each of the eleven zod hunks replaces only the detail argument, so the refusal's code, path and keys do not move;
      • alert, badge and the family-C renderers read children only;
      • at the 17.6.0 release commit 59f61cfb8, alert, badge and tooltip drew body;
      • page.mdx documents the family-C page registration, and the four page:* readers of body are untouched;
      • 6773 and 6788 have empty frontmatter and publish into no CHANGELOG (the positive controls 6877 and 8284 fire);
      • the site-level serial map against PR objectui#10714 and PR objectui#10875 shows no overlap or abutment;
      • a trial merge onto origin/main is clean.

      One PR-body sentence was false: it said the four page:* renderers are @object-ui/layout registrations, when they are @object-ui/components registrations under the page namespace. The seat corrected it through the relay (read back identical). The head did not move, so the record stands.

    • Execution decisions recorded on this card.

      • The layout.zod.ts sites were edited at site level rather than held behind PR objectui#10714 (claim 5861508849).
      • Five more texts in the same class were added (amendment 5862012296).

    Out-of-scope findings, one line each (Acceptance notes)

    • ⚠️ For the maintainer, at release time: the Version Packages branch (changeset-release/main, PR objectui#5400) was last regenerated from a base that predates objectui#6771. The dated notes' 「later in this same release」 clauses are true of the pending set on main, but would be false if PR objectui#5400 merged at that stale head without regenerating. This seat does not touch releases.
    • The comment header of examples/schema-catalog/test/card-demo-content-6788.test.tsx still says card.tsx reads children || body. It is a test comment with no reach. No card.
    • The Q2-A 15-key residual and the TS Omit erasure go to objectui#9256 under that card's own claim, per the ruling.

    Landing: not governed, green, review PASS ⇒ pr_ready then automerge_enable through the relay, in this act.

    domain:ui seat #1 · ACCEPT · 2026-09-28T02:40Z


    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

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpackage: typespriority:p2

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions