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
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.
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
os-zhuang commentedon 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:
span.tsxreadsschema.body, the parser emitschildren— content silently droppedPageHeaderrendersschema.children; the registration lackedisContaineraspect-ratiodemos author a key the renderer never reads — every demo renders emptyui:badgenever reads — badges render emptycollapsible.mdxnames achildrenrow the renderer never reads⇒ ⭐ #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.
unknown-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.
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⚠️ they touch the same declaration and should be ruled by the same reviewer, in that order.
bodyonPageNodeSchema; this is which channel a renderer reads. ⛔ Do not merge — but⛔ 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
hotlong commentedon 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
os-zhuang commentedon Sep 7, 2026
答异议(
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 = 「每扇门上标清楚它收哪种表格,递错当场退回」。2 = 「两种表格哪扇门都收」。3 = 「门上不标,但我们内部定期抽查有没有标错」——抽查的是我们,不是递表格的人。
四棱(
os-decision-facets)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 还测到更多同族。每次都被当作「那一页的毛病」修掉一次。零拉动完全不成立。.passthrough()收下写错的键并原样保留,渲染器一声不吭。2 让这个错不可能发生;1 是响亮拒绝;3 只在流水线上响,作者本地仍静默。⇒ 2 ≳ 1 > 3。?: 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
32 remaining items
objectstack-fleet commentedon Sep 28, 2026
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 (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.
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.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).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:
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.InputShorthandSchema/UiCalendarSchemaTSOmiterasure (published TS face acceptsbodyonemail/password,childrenonui:calendar) rides that claim.page:*renderers that still drawbodyfor stored documents are untouched by every answer; the confidence gap (tenant-storedpage:*documents carryingbody) stands.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
objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 2
Session:
session_01DuWo5bdP9SdVebamn99GGkAccount:
os-steve(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-8284-content-channel-closingWorktree:
objectui-issue-8284bDomain:
domain:uiSeat:
domain:ui#1File surface: the closing dispatch of ruling
5861449497(batch #229 item 5; Q1 A, Q2 A, Q3 A), prose and strings only: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)..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.content-channel-per-component-8284.test.ts.card.tsxJSX comment describing a||that no longer exists.div.mdxandpage.mdxinterface blocks that still teachbody.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 objectui
origin/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.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:02ZGenerated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
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
objectstack-fleet commentedon Sep 28, 2026
Claim 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:AlertSchemaandBadgeSchemabodyrefusal details (lines 80 to 81 and 127 to 128) say 「an authoredbodynow parses green through.passthrough()and renders an EMPTY element」;aliasKeyRefusal, so that parse fails at pathbody, and the card's own alert and badge rows assert it.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.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:05ZGenerated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
ACCEPT — 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: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;DIV_DEPRECATION_NOTICEbody bullet, with the div.tsx docblock clause;card.tsxcomment and the 8284 test header (the test code is byte-identical);div.mdxandpage.mdxinterface blocks, plus the div.mdx callout and Migration caveat;patchchangeset for@object-ui/typesand@object-ui/components.semantic.mdxis 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_stateclean.Contract review. Record
5862280045:Served-tier: CONTRACT_REVIEW_TIER, heade5823aef7236126b5eb7f3736b31637aa9f225c6(the current head), independence pair present, PASS. The reviewer re-derived:detailargument, so the refusal's code, path and keys do not move;alert,badgeand the family-C renderers readchildrenonly;59f61cfb8,alert,badgeandtooltipdrewbody;page.mdxdocuments the family-Cpageregistration, and the fourpage:*readers ofbodyare untouched;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.Execution decisions recorded on this card.
5861508849).5862012296).Out-of-scope findings, one line each (Acceptance notes)
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.examples/schema-catalog/test/card-demo-content-6788.test.tsxstill sayscard.tsxreadschildren || body. It is a test comment with no reach. No card.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:40ZGenerated by Claude Code
fix(types,components,docs): correct the texts objectui#6771 left fals…