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

stack 渲染器读一个从未声明的 spacing 键,catalog 里 135 个节点照着它写 #4890

Closed

Description

@yinlianghui

发现于 #4003 的实施,不在该 PR 处理 —— 那一单只把 div 转成布局类型并一律写声明键 gap,没有碰既有 stack 节点。

现象

StackSchema 继承自 FlexSchema,声明的间距键只有 gap:

  • packages/types/src/layout.ts:180-182 —— export interface StackSchema extends Omit<FlexSchema, 'type'> { type: 'stack'; }
  • FlexSchema 的键:direction / justify / align / gap / wrap / children

spacing 不在其中。但渲染器额外读它,还特意用 as any 绕过类型:

  • packages/components/src/renderers/layout/stack.tsx:25 —— const gap = schema.gap ?? (schema as any).spacing ?? 2;

于是 spacing 成了一个只存在于 consumer 里的第二套事实契约。catalog 里实测 135 个 stack 节点、39 个文件写的是 spacing 而不是 gap(例如 marketing/features-grid.json 的 {"type":"stack","spacing":3}、auth/*.json 全系列、actions/action-toolbar.json)。

与 #4001 的关系:同一个病,另一种表现

#4001 是"未声明的键被静默丢弃"(cols → 列数丢失,渲染成 2 列)。这条是同一个病的宽容变体:未声明的键被consumer 接住了,所以渲染看起来是对的,没人会去查,错的写法就一直传播 —— 而 #4001 正文说过,"碰巧看起来对"的那一类是最坏的一类。

AGENTS.md #0.1 直接点名这个形状:"宽容的 fallback 会把错写法固化成第二套事实契约,稀释 spec,并掩盖 producer 的 bug —— 一套严格契约胜过 N 种方言。"

今天没有用户撞到,但作者面已经被教坏

修法方向(契约优先)

改 producer:135 个节点 spacing → gap,然后删掉 stack.tsx:25 的 (schema as any).spacing ?? 那一截。⛔ 不要反过来把 spacing 补进 StackSchema 来"合法化" —— 那是把一个纯粹多余的别名提升成公共契约,gap 已经在那里,两个名字做同一件事只会让 AI 作者继续猜。

注意:改完之后渲染不变(两条路径本来就归到同一个 gap),所以这是一次纯机械替换,适合和 #4003 之后的 catalog sweep 合并成一张卡。#4003 已经留下 examples/schema-catalog/test/layout-props-conversion.test.tsx 这个位置,禁令加在那里最省。

参考位置

  • packages/types/src/layout.ts:180-182(StackSchema,无 spacing)
  • packages/components/src/renderers/layout/stack.tsx:25((schema as any).spacing)
  • packages/components/src/renderers/layout/flex.tsx(同族,不读 spacing)
  • packages/components/src/renderers/layout/stack.tsx:98-103(注册 inputs 只有 gap,与渲染器读的键已不一致)
  • examples/schema-catalog/src/schemas/**(135 个命中节点)

关联:#4001 / #4003 / #3965

Activity

  1. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Triage (concentrated finding round): promoted finding → pm:queue as a member of the sweep anchored at #4891 (same catalog file surface, same ratchet landing spot). Claim and dispatch happen on #4891; this card stays labelled but is not an independent dispatch candidate. Direction as the card states, contract-first: producer-side spacing → gap on the 135 nodes, then delete the (schema as any).spacing consumer leg — do not legalize spacing into StackSchema.

    本评论来自分诊座位 Routine (session session_018euHiF12oV8iSfYdjVioUF).


    Generated by Claude Code

  2. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 21, 2026
  3. os-sales commented on Aug 22, 2026

    @os-sales
    Collaborator

    Covered by the claim on #4891 — domain:ui execution seat, round 15.

    • Session: session_012u2pRjcqAYtoEjgr3wwhnK
    • Branch: claude/issue-4891-catalog-layout-props-sweep

    Per triage (comment 5335896919) this card is a member of the sweep anchored at #4891, not an independent dispatch candidate, so the claim lives there and one PR covers both. Recording it here so no other seat reads this card as unclaimed.

    In scope for that PR from this card: the 135-node spacing → gap rename and the stack.tsx alias removal, in triage's fixed order — producer-side rename first, then delete the (schema as any).spacing consumer leg, and do not legalize spacing into StackSchema.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:queue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions