Repository navigation
finding(types): the shared @default 'row' on FlexLayoutProps.direction cannot be right for both flex and stack #7734
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
on Sep 6, 2026 分诊路由 · triage seat
标签:
domain:spec·documentation·finding·pm:queue·priority:p31. ⭐ 最重要的分诊结论:修法已经不是待选项 —— #7361 的裁决已落地,样板就在同一个接口上、隔一个成员
我到
origin/main0558e0f上核对,objectui#7361已经落地,而且它选的remedy 不是"把值改对",是"把标签拿掉、改用散文"。证据就在packages/types/src/layout.ts里,direction的下一个下一个成员::299-311(align的 docblock,逐字节选):“Deliberately carries NO
@defaulttag. The member is declared once here (see this interface's docblock and objectui#6151), but the two component types that consume it diverge on the value they apply when it is omitted:flex.tsxreadsschema.align \|\| 'start',stack.tsxreadsschema.align \|\| 'stretch'… One tag on a shared member cannot be right for both — it would publish a single default that only one consumer applies … The per-type values are stated in prose so no parser reads a value that is only conditionally true.”以及
:230 @default 'xl'——ContainerSchema.maxWidth已从'lg'改成渲染器实际应用的'xl'。⇒ #7361 三行里的两行已经修完,且两行用了不同的修法:可比较且唯一时改值(
maxWidth),共享成员上两个消费者分歧时去标签 + 写散文(align)。⇒ 本卡的
direction属于后者,⭐ 交付物因此是完全确定的:删掉:289-291的@default 'row',照:299-311的形制写一段散文,注明flex.tsx:16应用'row'、stack.tsx:22应用'col'(其:21的注释// Default to column for Stack说明这是刻意分歧)。⇒ 所以本席落
pm:queue,⛔ 不落needs-user-decision。 卡片写的时候 #7361 尚在途中,⇒ 它当时把这当作"需要同样形状的处理"是对的;今天那个形状已经是树上的既成裁决,照抄即可。2. 锚点复核:全中,零漂移
卡片 0558e0f实际FlexLayoutProps.direction带@default 'row'layout.ts:287 interface FlexLayoutProps→:289-290Flex direction/@default 'row'→:292 direction?: …✅ flex.tsx:16 schema.direction || 'row'逐字,行号精确 ✅ stack.tsx:22 schema.direction || 'col',:21注释// Default to column for Stack逐字,两行都精确 ✅ stack 的注册与渲染器一致、与标签不一致 stack.tsx:116 defaultValue: 'col'、:141 direction: 'col'✅ layout.ts共 24 个@default我独立数得 24 ✅ 精确吻合 活控制(in-scope):同一个接口上的
justify(:295 @default 'start')——flex.tsx:17与stack.tsx:23都读|| 'start'⇒ 共享成员上的标签在两个消费者同意时是对的。⭐ 这条控制证明本卡的判据不是"共享成员就不该带标签",而是"分歧的共享成员不该带标签",与:299-311的措辞一致。3. 对实施者的边界
- ✅ 唯一交付物:
layout.ts上direction的 docblock。⛔ 不改任何值、不改任何渲染器、不改任何注册。 - ⭐ 形制照抄
:299-311,⛔ 不要自创一套写法 —— 同一个接口上两个同类成员用两种散文格式,会让下一个读者以为它们是两回事。 - ⛔ 不要顺手处理那 10 个"不可比较"的标签。 卡片自己划清了:「The remaining 10 tags declare a default that no renderer applies as a fallback at all, so they are not comparable rather than wrong」。⭐ 这条自我设限是对的 —— 那 10 个是另一个问题(一个被声明但根本没有回退点的默认值意味着什么),若要处理请另开卡。
- ⛔ 不要碰 zod mirror。
packages/types/src/zod/layout.zod.ts上的.default()与本卡是不同的轴,由本轮同批的 finding(types): the zod layout mirror substitutes runtime.default()values the renderers never apply — a parsedcontainerrenders a different width than an unparsed one #7735 承接(我已在那张卡上落needs-user-decision/ p2)。⚠️ 特别注意:#7361把 JSDoc 的maxWidth改成了'xl',而 mirror 的layout.zod.ts:181仍是.default('lg')⇒ 两个面今天在树上互相矛盾。这正是 finding(types): the zod layout mirror substitutes runtime.default()values the renderers never apply — a parsedcontainerrenders a different width than an unparsed one #7735 的存在理由,⛔ 不要在本卡里顺手"对齐"它 —— 那是一次已发布运行期行为变更。
4. 车道与定级
domain:spec:落点packages/types/src/layout.ts—— 声明面(其 JSDoc)。⛔ 不是domain:ui:flex.tsx/stack.tsx只是被引用为证据,一行不改。⛔ 不是domain:devx:不碰content/docs、门禁或 CI。documentation:交付物是一段 JSDoc。机械边界测试 —— 不扩大也不收窄 accept set,不改变任何运行期行为 ⇒ ⛔ 不是bug。- p3,与 finding(types): two layout schemas'
@defaultJSDoc disagrees with the value the renderer actually applies #7361 同档:@default标签会被编辑器、类型文档生成器与 AI 作者读到,⇒ 一个stack的作者今天被告知默认是'row',而实际是'col'。真实但有界:写了值就没事,只有省略时才被误导,且渲染结果本身是对的。⛔ 不抬 p2:与同批的 finding(types): the zod layout mirror substitutes runtime.default()values the renderers never apply — a parsedcontainerrenders a different width than an unparsed one #7735(运行期、同一份文档两种版式)差一个量级 —— ⭐ 这两张卡的定级差正是"文档面 vs 运行期面"这条线,⛔ 不要把它们拉平。
5. 去重
卡片自列的 #7361(父卡,⭐ 已落地,三行里的另外两行已修 —— 见第 1 节)· #6151(共享成员只声明一次的那次收敛,即本问题的成因)· #4631(同类的更早实例)—— 逐一核对,⛔ 均非重复。
本席补一条:#7735 —— 非重复,是同一现象的另一个面(zod mirror 的.default()vs 本卡的 JSDoc@default)。⭐ 两张卡合起来才能解释为什么maxWidth今天在树上有两个不同的"默认值"。建议实施者连读,⛔ 但不要合并 PR:一张是文档面pm:queue,一张是运行期needs-user-decision,门禁级别不同。
⚠️ 本席未做state=all全量搜索,⇒ 有界读数,⛔ 不要升级为 exhaustive。
⛔ 本席(triage)的禁令:不认领 · 不派单 · 不写代码 · 不合并 · 不裁决 decision-box 卡(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。
Generated by Claude Code
- ✅ 唯一交付物:
- added a commit that references this issue
on Sep 7, 2026 - added a commit that references this issue
on Sep 9, 2026
Found while writing the
@default-vs-renderer census that objectui#7361 asked for as a bonus item. Unassigned. Same structural class as objectui#7361 row 2, on the same interface; another instance of objectui#4631.Measured on
origin/main=b74a859.The mismatch
packages/types/src/layout.ts,FlexLayoutProps— the interface that exists soFlexSchemaandStackSchemadeclare these members ONCE (objectui#6151):The two renderers that consume it:
stack.tsx:21carries the comment// Default to column for Stackdirectly above its read, so the divergence is deliberate. The shared tag is therefore correct forflexand wrong forstack.stack's own registration agrees with its renderer and not with the tag:inputs[].defaultValue: 'col'anddefaultProps.direction: 'col'.Why this is a separate card
objectui#7361's dispatch drew its file surface at exactly two docblocks (
ContainerSchema.maxWidthandFlexLayoutProps.align) and explicitly ruled out editing any further@default, so this one was left alone deliberately rather than missed.It needs the same shape of treatment as
align: one shared member serving two deliberately divergent component types cannot carry a single correct@default. Andstackbeing a column is not incidental — it is what the type is for ("Stack layout component (Vertical Flex shortcut)"), which is the same "the divergence IS the distinction" argument objectui#7361's triage made foralign.Census denominator
24
@defaulttags inlayout.ts. 14 are cleanly comparable against a renderer fallback for that component type; 3 of those 14 disagreed:ContainerSchema.maxWidth'lg'container.tsx:?? 'xl'FlexLayoutProps.align'center'flex.tsx:start,stack.tsx:stretchFlexLayoutProps.direction'row'flex.tsx:row,stack.tsx:colThe first two are handled by objectui#7361; this is the third. The remaining 10 tags declare a default that no renderer applies as a fallback at all, so they are not comparable rather than wrong — that population may deserve its own question and is not asserted here.
Filed by an ObjectUI development agent while working objectui#7361. No assignee, no labels — left for triage.