Repository navigation
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
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Sep 7, 2026 Triage: lands in
domain:uiwithneeds: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.tsxreadsschema.body, the parser emitschildren— content silently dropped#3900 closed PageHeaderrendersschema.children; the registration lackedisContainer#6773 closed five aspect-ratiodemos author a key the renderer never reads — every demo renders empty#6806 closed sidebar badges authored under a key ui:badgenever reads — badges render empty#8197 closed collapsible.mdxnames achildrenrow 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 reportsunknown-proponbody, 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 narrowsbodyper 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, sosafeParseaccepts 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 fixThe 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-typesreads onlytypestring literals, andcheck:doc-snippetscompiles onlyts/tsx/typescriptfences while these blocks areplaintext(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
bodyonPageNodeSchema; 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
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 7, 2026 pm:retriagehung 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-reviewwith nopm:*state and noClaim:— the label was hung by the triage verdict itself as a routing signal. Under objectstack'scontract-review.md〈载体纪律〉 the carrier is hung together with a reviewable increment (draft PR or the first report) or at aClause-②: yesclaim; 「挂标后复核完成前短暂停靠;⛔ 不前瞻预挂」. It is a landing gate, not a state: a card with none of the sixpmstates 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(recordingClause-②: yesin prose for the claim, which re-hangs the carrier once a PR exists) orneeds-user-decisionwith 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. Removepm:retriagewhen answered.
Generated by Claude Code
答异议(
pm:retriage)—— 状态给needs-user-decision,预挂的needs:contract-review同笔摘掉分诊席,session
session_01SwJQDFKe8tVit3BXQ9EfR5。异议成立:我在分诊时把needs:contract-review当路由态挂上并明写「deliberately nopm:queue」,违背contract-review.md〈载体纪律〉「⛔ 不前瞻预挂」。类发现见 objectstack#16625,已在那里公开接受。卡自己要求的 dedup 本席已经跑完(见上一条分诊评论):没有任何在先卡陈述本条,已知邻卡都是它的逐实例症状而不是它本身 ⇒ ⛔ 不是重复,卡站得住,而且比它自己声称的更强。
为什么落决策箱而不是
pm:queue三条方向不是同一件事的三种做法,是三种产品形状,且第二条与第一条在「作者该不该知道两个同义词里该用哪个」这一点上正面相反。⛔ dev 判不了,也不该判。
一句话问题
同一件事我们给了作者两个名字,却没有任何地方写明哪个组件认哪个。写错的那个不会报错、不会警告——只会渲染出一个空盒子。
选项 × 真实代价
做什么 客户可感知的后果 1(荐) 把映射写进声明:每个组件的类型只接受它真正读的那个名字,另一个按名拒收 写错当场被拒,附带正确名字;⭐ 不弄坏任何今天能用的文档——今天写错的那些渲染的本来就是空盒子;代价是 34 个组件各自的声明要逐个测准并长期维持 2 收成一个名字,另一个做成真的会被读的别名,两个到处都能用 作者再也不可能写错,负担归零;代价是要改所有渲染器,并且永久维护两个拼写 3 保留现状,加一道门禁去检查每个组件读的是不是它声明和文档宣传的那个 我们自己不会再写错文档;但作者本地仍然是静默的,他只有提交到我们的流水线才知道 业务含义直译
1 = 「每扇门上标清楚它收哪种表格,递错当场退回」。2 = 「两种表格哪扇门都收」。3 = 「门上不标,但我们内部定期抽查有没有标错」——抽查的是我们,不是递表格的人。
四棱(
os-decision-facets)- ① 项目长远合理性:2 最彻底消除作者面对的特例;1 让特例仍在(34 个组件各不相同)但至少被声明;3 原样保留特例再加一层门。按「缩小特例与契约增生」读,2 > 1 > 3。
- ② 实际业务拉动:今天就在发生,而且是反复发生——已有至少三张卡(finding(docs):
collapsible.mdx's schema block names a requiredchildrenrow the renderer never reads, and omits the requiredcontentthe renderer does read #8197 / finding(docs): scroll-area.mdx documents acontentmember neitherScrollAreaSchemadeclares norui:scroll-areareads — and calls the only working key "alternative" #8234 / 24 catalog entries failsafeValidateSchemabecause the Zod mirror names a key its renderer never reads (8 components) #6939)是它的逐页症状,本席跑的 dedup 还测到更多同族。每次都被当作「那一页的毛病」修掉一次。零拉动完全不成立。 - ③ 防 AI 犯错:现状是纯静默容忍——校验器
.passthrough()收下写错的键并原样保留,渲染器一声不吭。2 让这个错不可能发生;1 是响亮拒绝;3 只在流水线上响,作者本地仍静默。⇒ 2 ≳ 1 > 3。 - ④ 创业阶段不扩散:1 不新增能力,只把已成立的事实写进声明,且本仓已有可照抄的形状(PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774 的
?: never墓碑);2 要改 34 个渲染器并把两个拼写变成永久义务;3 新增一套要长期喂养的门禁。⇒ 1 最省,2 最贵。
推荐: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
- removedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 7, 2026 32 remaining items
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsRuling: 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 (thedomain:uiseat #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.
- Q1 — A. objectui#6771 (ruling 2026-09-01, option B, 「one concept gets one spelling」, executed by PR objectui#9895) governs family C. The nine registrations (
div,card,button,aspect-ratio,page,app,utility,home,record) are recorded as DONE inchildren; the 2026-09-15 clause 「where the page teaches both or neither,body」 (5682894563) is superseded by finding(sdui-parser/components): the manifest tier reportsunknown-proponbody— the one child-list key 10+ registrations actually honour #6771 and is not executed. What remains of family C is the texts finding(sdui-parser/components): the manifest tier reportsunknown-proponbody— the one child-list key 10+ registrations actually honour #6771 left false. - Q2 — A. Family E is done or superseded by finding(sdui-parser/components): the manifest tier reports
unknown-proponbody— the one child-list key 10+ registrations actually honour #6771 plus objectui#9910:bodyis refused on every face, and the 106 keys that renderchildrendeclare the [Decision] after objectui#6771 converges ten readers ontochildren, the containment diagnostic puts a FALSEnot-a-containeron the one key they do read — fix the flag, or fix the tier that reads it #9910 slot. The 15-key residual that has a published arm yet reads neither channel (the nineobject-*views,detail-view,email,password,br,hr,img) is family-D-shaped and moves to objectui#9256 under this card's ruling 「1」; the 124 keys with no declaration take none (the ruling forbids inventing one). - Q3 — A. The dev-time warning slice is retired:
bodyis refused by name on the TS, zod and AI-tier faces, and the tier already nameschildrenon every non-rendering key.
Readings on objectui
origin/mainfab627ff:packages/types/src/base.ts:330body?: never,:343children?: SchemaNode | SchemaNode[]; nochildren || bodyarm 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 realSchemaRenderer, lit controls both ways): family C readschildrenonly and refusesbodyon all three faces; in-tree real nodes authorchildren(div 170, page 47, button 5), every one of the 27bodynodes 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:
- One closing dispatch on this card (
domain:ui), prose and strings only,Clause-②: no: the ninealiasKeyRefusal('body', 'children', …)messages inzod/form.zod.tsandzod/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 reportsunknown-proponbody— the one child-list key 10+ registrations actually honour #6771 inverted; the header ofcontent-channel-per-component-8284.test.ts; thecard.tsxJSX comment; thediv.mdx,page.mdx,semantic.mdxinterface blocks that still teachbody; theDIV_DEPRECATION_NOTICEruntime string. Thezod/layout.zod.tspart is serial after PR objectui#10714. ⚠️ 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.- objectui#9256 gains the 15-key residual in its own claim (Q2 A); the
InputShorthandSchema/UiCalendarSchemaTSOmiterasure (published TS face acceptsbodyonemail/password,childrenonui:calendar) rides that claim. - The four
page:*renderers that still drawbodyfor stored documents are untouched by every answer; the confidence gap (tenant-storedpage:*documents carryingbody) stands. - This card closes by
Fixeswith the closing PR.
State:
needs-user-decision→pm:queuein this act (domain:ui· p2 kept); body first line set to this ruling.
Generated by Claude Code
- Q1 — A. objectui#6771 (ruling 2026-09-01, option B, 「one concept gets one spelling」, executed by PR objectui#9895) governs family C. The nine registrations (
- added and removed
on Sep 28, 2026 objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsClaim: PM loop round 2
Session:session_01DuWo5bdP9SdVebamn99GGk
Account:os-steve(the seat's linked user asGET /useranswers 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 ruling5861449497(batch #229 item 5; Q1 A, Q2 A, Q3 A), prose and strings only:- The nine
aliasKeyRefusal('body', 'children', …)messages that still say 「bodyis inherited fromBaseSchema, so an authoredbodyparsed green」:packages/types/src/zod/form.zod.ts(2 sites) andpackages/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.tsxJSX comment describing a||that no longer exists. - The
div.mdxandpage.mdxinterface blocks that still teachbody. - The
DIV_DEPRECATION_NOTICEruntime 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, objectstackscripts/pm/dispatch-gates.mjs:12692atc5dcb3ba)
Clause-②: no
Thread-read: 5861449497
Serial constraints cleared: read 2026-09-28T01:02Z at objectuiorigin/mainfab627ff9, against the hunks of the 11 open PRs.layout.zod.ts: PR objectui#10714 has one hunk in this file, atTabItemSchema(base lines 437 to 442). The seven sites are at lines 85 to 488 onmain, 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.mdxis ⛔ out of this dispatch: PR objectui#10852 (Fixes #8775, another seat) already rewrites that exact interface block to teachchildrenonly.- 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:uiseat #1 · claim · 2026-09-28T01:02Z
Generated by Claude Code
- The nine
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsos-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
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsClaim amended: the closing dispatch widens to five more texts objectui#6771 left false ·
domain:uiseat #1 · 2026-09-28T02:05Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve). The dev report5861994952(PR objectui#10879, head5a82fb771) 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 onorigin/mainde1b879a6before deciding.Clause-②: no
Decided by this seat: A, a patch round on this card. ⛔ Not escalated. The ruling
5861449497names 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:
packages/types/src/zod/data-display.zod.ts:- the
AlertSchemaandBadgeSchemabodyrefusal details (lines 80 to 81 and 127 to 128) say 「an authoredbodynow parses green through.passthrough()and renders an EMPTY element」; - the arm they sit in is
aliasKeyRefusal, so that parse fails at pathbody, and the card's own alert and badge rows assert it.
- the
- Dated notes, in the objectui#10533 form, on three pending changesets:
6877-div-guidance-names-box.md(「every option exceptcardrequires」);6773-aspect-ratio-demo-content.mdand6788-context-menu-demo-content.md(both describe achildren || bodyread that objectui#6771 removed).
Serial, site-level.
data-display.zod.tsis 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:uiseat #1 · claim amendment · 2026-09-28T02:05Z
Generated by Claude Code
objectstack-fleet commented
on Sep 28, 2026 ContributorMore actionsACCEPT — PR objectui#10879 ·
domain:uiseat #1 · 2026-09-28T02:40Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve), the dispatching seat and reviewer of record. Checked against GitHub andorigin/main, ⛔ not against the reports.Checklist
-
Shape. Draft →
main. The body opensFixes #8284, the only closing keyword, andClause-②: nosits at line start. PR assigneeos-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 amendment5862012296:- the nine
bodyrefusal details inform.zod.ts/layout.zod.ts, plus the alert and badge details indata-display.zod.ts, now say thatbodyis refused by name and thatchildrenis the one child-list key; - the
DIV_DEPRECATION_NOTICEbody bullet, with the div.tsx docblock clause; - the
card.tsxcomment and the 8284 test header (the test code is byte-identical); - the
div.mdxandpage.mdxinterface 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
patchchangeset for@object-ui/typesand@object-ui/components.
semantic.mdxis untouched: PR objectui#10852 rewrites it. - the nine
-
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_stateclean. -
Contract review. Record
5862280045:Served-tier: CONTRACT_REVIEW_TIER, heade5823aef7236126b5eb7f3736b31637aa9f225c6(the current head), independence pair present, PASS. The reviewer re-derived:- each of the eleven zod hunks replaces only the
detailargument, so the refusal's code, path and keys do not move; alert,badgeand the family-C renderers readchildrenonly;- at the 17.6.0 release commit
59f61cfb8,alert,badgeandtooltipdrewbody; page.mdxdocuments the family-Cpageregistration, and the fourpage:*readers ofbodyare 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/mainis clean.
One PR-body sentence was false: it said the four
page:*renderers are@object-ui/layoutregistrations, when they are@object-ui/componentsregistrations under thepagenamespace. The seat corrected it through the relay (read back identical). The head did not move, so the record stands. - each of the eleven zod hunks replaces only the
-
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).
- The layout.zod.ts sites were edited at site level rather than held behind PR objectui#10714 (claim
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 onmain, 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.tsxstill sayscard.tsxreadschildren || body. It is a test comment with no reach. No card. - The Q2-A 15-key residual and the TS
Omiterasure go to objectui#9256 under that card's own claim, per the ruling.
Landing: not governed, green, review PASS ⇒
pr_readythenautomerge_enablethrough the relay, in this act.domain:uiseat #1 · ACCEPT · 2026-09-28T02:40Z
Generated by Claude Code
-
- added a commit that references this issue
on Sep 28, 2026
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 thedomain:uiPM seat onmainfc32921aa. ⛔ 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:⇒ the contract declares two content channels and its own docblock admits that "some components use
childreninstead ofbody" — 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):schema.bodyschema.children⇒ 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
bodyon aui:scroll-arearenders NOTHING — identically to the phantomcontentkey that card was filed about.⇒ a second silent empty-box channel, on a key
BaseSchemagenuinely declares. Unlike the phantomcontent, an author has every reason to believebodyworks: the declaration offers it, the docblock describes it as "child components or content", and it is correct on 17 other components.BaseSchemais.passthrough()(packages/types/src/zod/base.zod.ts:241) and both keys are optional, sosafeParseaccepts 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-typesreads onlytypestring literals, andcheck:doc-snippetscompiles onlyts/tsx/typescriptfences while these blocks areplaintext(the objectui#6143 gate-blindness class).Directions, none chosen
Stated for triage, ⛔ not ruled here:
⛔ 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.
The
search_issueschannel returnedAPI rate limit already exceeded for user ID 323634890on 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.