Skip to content

finding(gate): check:react-blocks-declaration-parity compares only the per-block PROPS half of a node contract, so a node-level spec key reads as an invented input — objectui is about to trip it #13192

Description

@os-sales

Filed by the objectui domain:ui execution seat (PM session session_01CRJge11jso9TpXRWFt1Z49) on behalf of the objectui#6678 implementer, which measured all of this but could not file it: its dedup search returned API rate limit already exceeded for user ID 319429713, and it declined to file blind. Carrying it across so the reading is not lost. Filed unassigned and ungraded — domain:*, type and grading are this repo's triage's to produce, not mine.

Dedup before filing: repo-scoped search returned 13 related results ⇒ the engine answers, so the zero on this specific defect is a reading. Nearest neighbours, none of them this: #7121 (closed) tracked the consumption side of the very same key — "PageComponentSchema.dataSource 在剩余 object-bound public block 上仍无人消费" — while this is the declaration side and the gate that misjudges it; #12039 and #12344 are ComponentPropsMap row problems of a different shape.

The gate's premise, and where it stops being true

check:react-blocks-declaration-parity compares a block's registry-declared inputs against ComponentPropsMap[type], and reports an input the map does not carry as "declares an input the spec does not accept."

That premise holds only while every key a node may carry is a per-block key. dataSource is not:

  • it is declared once, on PageComponentSchema — the node-level contract, alongside type and className;
  • measured: PageComponentSchema.safeParse({ type: 'list-view', dataSource: {…} }) succeeds AND keeps the key;
  • ComponentPropsMap['object-grid'] has no dataSource among its 37 keys.

⇒ ComponentPropsMap[type] is the props half of a node's contract, not the whole of it. A node-level key therefore reads to this gate as an invented input, and the complaint is false rather than merely inconvenient.

Why it is about to matter here

objectui#6678 was ruled 2026-08-29 (maintainer, director batch #11) and landed as objectui PR #6767: blocks that wrap the runtime ElementDataSourceGate now declare dataSource, emitted mechanically at the wrapping seam. That is 17 renderers across 12 packages. ⇒ this gate will report a false parity failure on every one of them the next time it sees objectui's manifest.

objectui's own two parity gates hit exactly this and were corrected rather than exempted, on the measurement above. That correction cannot be made from objectui for the framework-side gate.

Suggested shape — mirroring what objectui already did

Derive the accepted set from PageComponentSchema's own key shape rather than a listed key. ⚠️ Implementation note the implementer left: it is a .pipe(), so read _def.in.

⭐ And pin the calibration, which is what stops the widening from turning the gate vacuous: dataSource and className accepted; objectName, viewName and an invented key still refused. objectui's corrected gates carry exactly that discrimination.

Two shapes deliberately not recommended

  • Per-block exemptions naming this issue — leaves a false gate standing behind an allowlist that needs a new entry every time a block starts wrapping the seam. That is the hand-kept-copies drift objectui#6678's ruling refused, in another costume.
  • Moving dataSource into each block's ComponentPropsMap — the key is declared once on PageComponentSchema precisely because it applies to every page component; copying it into 25+ per-block props schemas re-creates the hand-kept copies as spec text.

What is NOT measured

  • Whether this gate has other node-level keys already in the same position (className was checked and accepted; the rest of PageComponentSchema's node-level keys were not swept).
  • Whether any other consumer reads ComponentPropsMap[type] as if it were the whole node contract. This card is about the one gate that was measured.
  • The gate's own file path and current shape — read from this repo, not asserted here.

Backlink

objectui PR #6767 (the landing change) · objectui#6678 (the ruled card) · #7121 (the consumption half of the same key, closed)

Activity

  1. huangyiirene commented on Aug 29, 2026

    @huangyiirene
    Collaborator

    定级:pm:queue · domain:spec · tooling · priority:p1。finding 已离标。

    ⚠️ 车道判 domain:spec,不是 domain:devx —— 路径会骗人

    落点从树上读出:

    packages/spec/scripts/check-react-blocks-declaration-parity.ts
    packages/spec/scripts/check-react-blocks-declaration-parity.test.ts
    packages/spec/scripts/build-react-blocks-contract.ts
    

    ⇒ 这个门禁住在 packages/spec 内部。本仓车道表:domain:spec = packages/spec 整体;domain:devx 只覆盖根 scripts/ 的门禁类脚本。

    ⛔ "是个门禁 ⇒ devx" 是错的推断,scripts/ 这个路径片段在这里是陷阱。(同一条规则此前用在 packages/spec/scripts/liveness/check-liveness.mts 上。)我本轮先按直觉写了 devx,查树之后改判——记在这里,因为下一个人会同样直觉出错。

    p1 的理由:它即将真的红

    卡的标题就说了 "objectui is about to trip it"。⇒ 这不是一个潜在缺陷,是一个有到期日的缺陷:门禁把节点级 spec 键读成"凭空发明的输入",而 objectui 正要写出那种节点。⇒ 一旦撞上,红的是对的那一方,而门禁是错的那一方。

    ⭐ 这是本周那一族的反向成员,和 #13110 同型:不是"该红不红",是"不该红却要红"。这类更贵——它会让一个正确的改动被挡住,而挡它的理由是假的,于是开发要么绕过门禁(坏),要么把正确的代码改坏来迁就它(更坏)。

    ⛔ 派发围栏

    1. ⛔ 不得放宽或关闭该门禁来让 objectui 通过。 门禁削弱是本仓人工地板 —— 分诊不能授权,开发不能自行执行。正确方向是让它比较完整的节点契约(节点级键 + per-block props 两半),而不是只比 props 那一半。
    2. ⚠️ 这是跨仓耦合:门禁在 objectstack,被它挡住的编写方在 objectui。⇒ 修好之前,objectui 侧那个改动会被一个假红挡住。排期上这条先行,⛔ 不要让 objectui 侧先绕。
    3. ⛔ 不要顺手动 skills/objectstack-ui/contracts/react-blocks.contract.json —— 那是治理面(skills/**),人工合并。⚠️ 若修复确实需要动它,拆成独立的 draft PR,⛔ 不搭在代码 PR 上。

    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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions