Skip to content

test(console): registry inputs 与 spec ComponentPropsMap 的 parity 门推到全仓,4 个 OFF-SPEC block 逐块判定 (#3797) - #3806

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3797-inputs-spec-parity
Aug 8, 2026
Merged

test(console): registry inputs 与 spec ComponentPropsMap 的 parity 门推到全仓,4 个 OFF-SPEC block 逐块判定 (#3797)#3806
yinlianghui merged 1 commit into
mainfrom
claude/issue-3797-inputs-spec-parity

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3797

两半件:门无条件成立并已落地;4 个 OFF-SPEC block 逐块以 origin/main 代码两向判定,结论全部落在 spec 一侧,因此本仓四个 block 的 inputs 一个字节都没动,转 objectstack 立单 + 挂显式豁免等上游。

核验基线:objectui origin/main @ c4c0ac8972c2efe69b11997dade1cc7655c15666(pin @objectstack/spec@^17.0.0-rc.5,也是 npm 上最新的已发布版本);objectstack origin/main @ ea1d9165d8d4b5c5d806e095f9604cb3731d4e62(只读)。


A. 全仓 parity 门

新增 apps/console/src/__tests__/registry-inputs-spec-parity.test.ts。把 PR #3795record:highlights 上落的单块检查(「declares no top-level input the spec does not accept」方向)推广到所有「ComponentPropsMap 有条目且本仓注册了非空 inputs」的 block。

期望值运行时从 spec 自身 shape 推导(specTopLevelKeys()ComponentPropsMap[type].shape,兼容 lazySchema() 代理),不复述键表 —— spec 增删键时门跟着动,而不是静默放宽。

放置位置及理由(也写进了测试头注):门需要的是产出发布物那一份完整注册图dev/manifest-dump.tsxsrc/register-plugins.ts + @object-ui/components 搭 manifest,本文件就导入这一对(与隔壁 public-contract.test.ts 同法),不自己攒一份会自说自话的清单。覆盖面不限于 public tier:packages/components/src/renderers/layout/page.tsx:462getKnownTypes() 在运行时现搭 JSX 页面校验 manifest,所以非 public 的 block(element:record_picker 不在 PUBLIC_BLOCKS 里)的 inputs 同样是活的 prop 白名单。

判定的 15 个 block(EXPECTED_COVERED,精确列表而非 toContain —— 危险方向是收缩):element:button / element:number / element:record_picker / element:text / element:text_input / page:accordion / page:card / page:header / page:tabs / record:activity / record:chatter / record:details / record:highlights / record:path / record:related_list。另有 10 个「有 spec 条目、已注册、inputs 为空」的 block 单独钉住(EXPECTED_WITHOUT_INPUTS),这样「声明面凭空消失」和「声明面长出方言」一样可见。

门共 6 类断言 / 21 个 test:

断言 作用
judges every spec-carried block… 非空性守卫:注册图掉了就红,不会在空集上全绿
pins the spec-carried blocks that are registered with no inputs 声明面消失可见
resolves a non-empty accepted key set for each covered block 守 derivation 本身:Zod 内部变了导致 .shape 读不到时,失败读起来是「修读取器」而不是「全仓回归」
BLOCK declares no top-level input the spec does not accept(it.each,15 条) 主断言
every exemption names a real declared input on a covered block 拼错的豁免键不能冒充「有意豁免」
every exemption states a reason and references a tracking issue 每条豁免必须带单号
carries no stale exemption 豁免会过期:spec 一旦声明该键,条目必须删,名单不会烂成永久 allowlist

显式豁免名单(8 条,全部带理由 + 单号)

豁免键 理由摘要
page:header.recordChrome 渲染器实读 containers.tsx:979,:1453 据此选裸 h1 布局;preview-samples.ts:68 / buildDefaultPageSchema.ts:413 今天就在写 → 等 objectstack#6776 补声明
page:header.showStar 实读 containers.tsx:980,:1531 传给 RecordTitleChip 关掉关注星 → objectstack#6776
page:header.showCopyId 实读 containers.tsx:981,:1532 传给 RecordTitleChip 关掉复制 ID → objectstack#6776
page:accordion.variant 实读 containers.tsx:734,:735 据此改每个面板边框类;渲染器注释原文即写 variant: 'card' 是作者 opt-in → objectstack#6776
page:tabs.tabStyle 实读 containers.tsx:381,且是扁平 SDUI 载体唯一能表达的拼法(详见下表)→ objectstack#6776
element:record_picker.labelField 上游 objectstack#5775 已声明,仅因 pin 落后而被 flag;pin 升上来后必须删本条
element:record_picker.valueField 同上
element:record_picker.label 同上

豁免的门槛写在代码注释里,不是「渲染器读它」——读它只说明这个键值得被声明在某处,不说明它值得被声明在契约拒绝它的地方。门槛是「该偏离已由一张具名的在办上游单持有」,因为 @objectstack/spec 不从本仓改(AGENTS.md #0 / #0.1)。


B. 4 个 OFF-SPEC block 逐块判定

三选一的输出:(1) renderer 真实读且用户可达 → 「spec 补声明」,本仓不动 spec,转 objectstack 立单 + 豁免;(2) renderer-only / 不读 → 撤下或留下并在 description 写明;(3) 两向拿不准 → needs_decision。

四块全部落 (1)。渲染器读点全在 packages/components/src/renderers/layout/containers.tsx,读的都是 schema.* / schema.properties.*(作者写的页面元数据);该 block 真正由宿主注入的东西走 RecordContext(headerSystemActions / isFavorite / onToggleFavorite)且故意没有出现在 inputs 里 —— 所以这几条不是 renderer-only 内部 prop,是作者配置项。

block input 判定 证据(file:line) 本仓动作 上游单
page:header recordChrome (1) spec 补声明 containers.tsx:979;消费 :1453(注释原文 Author hasn't opted out via recordChrome: false)决定「记录 chip 版页头」还是「裸 h1 版页头」。仓内已有作者:apps/console/src/preview-samples.ts:68properties: { title, recordChrome: false };packages/plugin-detail/src/synth/buildDefaultPageSchema.ts:413-414 在每个合成记录页页头产出它 不动声明面,进豁免 objectstack#6776
page:header showStar (1) containers.tsx:980;消费 :1531RecordTitleChip showStar(custom/RecordTitleChip.tsx) 同上 objectstack#6776
page:header showCopyId (1) containers.tsx:981;消费 :1532RecordTitleChip showCopyId(RecordTitleChip.tsx:47/64/114) 同上 objectstack#6776
page:tabs tabStyle (1),但上游是改名不是新增 containers.tsx:381 schema?.properties?.type || schema?.tabStyle || 'line' 同上 objectstack#6776(含两方案与代价)
page:accordion variant (1) containers.tsx:734 schema?.variant ?? schema?.properties?.variant ?? 'flush';消费 :735-736 决定每个面板 itemClass(flush = border-b last:border-b-0,card = 交给内部内容自己给边框),渲染结果肉眼可辨;渲染器注释原文:Authors opt in by setting variant: 'card' … on the schema 同上 objectstack#6776
element:record_picker labelField / valueField / label (1),上游已解决 见下 同上(等 pin) objectstack#5775(已完成)

page:tabs.tabStyle 为什么不是「撤下」也不是 needs_decision

spec 已经声明了这个概念,拼法是 type(PageTabsProps.type,enum line/card/pill,default line),所以这不是漏声明,是「一义两拼」,而且两种拼法渲染器都读、spec 那种优先。看起来该按 #0.1 直接撤 tabStyle,但两条本地动作都被证否:

  • 撤掉 tabStyle 会删掉扁平 SDUI 载体唯一能表达的拼法。packages/react/src/SchemaRenderer.tsx:251-270 故意不把 properties.type / properties.id 上提到节点上(会遮蔽组件分发键,注释点名说的就是页签视觉风格这个 case);扁平节点长成 { type: 'page:tabs', items: [...], tabStyle: 'card' },那里 type 是标签名。
  • 改成发布 type 会声明一个自家 parser 结构上无法校验的键:packages/sdui-parser/src/validate.ts:20-30BASE_PROPS'type',任何节点上都被当基础 prop 跳过。

所以剩下的杠杆只在 spec 侧,而「改名 typetabStyle(照 objectstack#5775 处理 displayFieldlabelField 的同形做法,往渲染器实读的拼法收敛)」还是「spec 同时声明别名」是本仓不该猜的契约决定 —— 两方案连代价一起写进 objectstack#6776 交上游拍,本仓侧不因此停摆(门无条件成立,该 input 挂豁免)。

element:record_picker:issue 的猜测对了一半,而且上游早修完了

issue 猜 labelField 是 spec displayField 的别名漂移。查 objectstack 侧 alias/conversion 登记(git -C /home/user/objectstack grep,origin/main)结论:

  • packages/spec/src/ui/component.zod.ts:715-786 现在把 labelField / valueField / label(以及 sort / limit / emptyText)全部声明好;
  • displayField / searchFields / multiple 转成了 retiredKey() 墓碑,由 objectstack#5775 / ADR-0087 D2 完成;
  • 收敛方向正是本仓渲染器实读的 labelField(renderers/basic/record-picker.tsx:80-81 props.labelField ?? 'name'),packages/spec/src/conversions/registry.ts:4710-4740displayFieldlabelField 的 conversion 条目。

所以本仓这三条 flag 纯粹是 pin 落后造成的:npm 上 @objectstack/spec 最新已发布版本是 17.0.0-rc.5,早于 #5775。两仓都没有活要干,只等 pin 升上来;carries no stale exemption 会在那一刻把这三条豁免顶红,强制删掉。

顺带修正 issue 正文一处误归因

issue 提示「page:header 的 inputs 在 #3226 / PR #3265 刚被收窄过,所以那三个可能是有意保留的 renderer-only prop」。核验为:PR #3265(d2363e710)动的是 packages/layout 里的遗留 kebab 别名 page-header(registerLayout()description input,对应 objectstack#4827),packages/components 里 canonical 的 page:header 那次完全没被碰过。没有任何「有意保留」的记录,这三条就是普通的未声明作者配置项 —— 也因此不适用 record:activity.showSubscriptionToggle 那条先例(那条是反方向:spec 声明了、渲染器不读,所以为保持双向 parity 留下并在 description 写明 KNOWN GAP)。

一处主动没做的事,写出来供 review 推翻:没有在 showStar / showCopyId / tabStyle / variantdescription 里加「本键当前未被 spec 声明」之类的话。理由:那等于把一条上游缺陷的临时说明发布进 sdui.manifest.json(AI 作者读的东西),objectstack#6776 一落地它就过期,而且没有任何门会强制删它。豁免名单里的理由才是有过期机制的那份记录。


验证

门的反向验证(方向先判后跑,四条)

探针 事先预判 实际
RV1:给 page:card(当前零 off-spec、零豁免)塞一个假 input bogusOffSpecProbe 只有 page:card 那条主断言红,点名该键 ✅ 一致
RV2:把 page:tabs.tabStyle 的豁免理由换成不含单号的一句话 主断言保持绿(证明豁免是真放行),every exemption states a reason… 红并点名该条 ✅ 一致(见下方「一次探针自身的失误」)
RV3:给 page:card.title(spec 确实接受的键)加一条豁免,模拟「上游已声明」 carries no stale exemption 红并点名,page:card 主断言保持绿 ✅ 一致
RV4:删掉 import '../register-plugins',模拟注册图丢失 非空性守卫红,点名掉出去的 6 个 record:*;test 总数从 21 掉到 15 ✅ 一致

RV1 输出:

FAIL … > page:card declares no top-level input the spec does not accept
AssertionError: expected [ 'bogusOffSpecProbe' ] to deeply equal []
 Test Files  1 failed (1)
      Tests  1 failed | 20 passed (21)

RV2 输出(注意 20 passed —— page:tabs 主断言仍绿):

FAIL … > every exemption states a reason and references a tracking issue
AssertionError: expected [ 'page:tabs.tabStyle' ] to deeply equal []
 Test Files  1 failed (1)
      Tests  1 failed | 20 passed (21)

RV3 输出:

FAIL … > carries no stale exemption — a declared key must lose its entry
AssertionError: expected [ 'page:card.title' ] to deeply equal []
 Test Files  1 failed (1)
      Tests  1 failed | 20 passed (21)

RV4 输出:

FAIL … > judges every spec-carried block that declares an authoring surface
AssertionError: expected [ 'element:button', …(8) ] to deeply equal [ 'element:button', …(14) ]
-   "record:activity",
-   "record:chatter",
-   "record:details",
-   "record:highlights",
-   "record:path",
-   "record:related_list",
 Test Files  1 failed (1)
      Tests  1 failed | 14 passed (15)

一次探针自身的失误,如实记下:RV2 第一次跑成了绿。原因不是断言弱,是探针建错了 —— 我只替换了理由字符串的前半句,尾巴上的 objectstack#6776 还在,/#\d+/ 照样命中。把整条理由换成不含任何单号的一句后才拿到预期的红。留在这里是因为「探针没造对」和「断言不管用」在输出上长得一模一样,而结论完全相反。

行为不回归

这一条在本 PR 里是空的,如实说明而不是编证据:四个 block 的 inputs 一个字节都没动,containers.tsx / record-picker.tsx 的渲染逻辑零改动(diff 只有一个新测试文件 + 一个 changeset),所以没有「撤下 input 后行为是否回归」可验。反向验证阶段临时塞进 containers.tsx 的探针已按原文件字节还原(git status 干净,只余新增文件)。与 PR #3791 新落的页头 CEL 代码零冲突 —— 本 PR 不碰 containers.tsx

为兜底仍跑了四个 block 的行为面 + PR #3795 的单块门 + PR #3265 的 layout 别名门,全绿:

pnpm exec vitest run packages/components/src/__tests__/page-header-actions.test.tsx \
  page-header-title / page-header-predicate-dialect / page-tabs-visibility \
  page-tabs-count-badge-i18n / page-card-i18n-title / page-variables \
  packages/plugin-detail/src/__tests__/recordHighlightsInputs.spec-parity.test.ts \
  packages/layout/src/__tests__/page-header-authorable-keys.test.tsx
 Test Files  9 passed (9)
      Tests  107 passed (107)

受影响包 + 新门(仓库根,flock + 4096MB + maxWorkers=2)

pnpm --workspace-concurrency=2 --filter '@object-ui/console^...' build 建依赖过滤集,防 TS2307 假红。

pnpm exec vitest run --project "@object-ui/console" --maxWorkers=2
 Test Files  28 passed (28)
      Tests  268 passed (268)

新门单跑:Test Files 1 passed (1) / Tests 21 passed (21)

type-check / lint / 仓库门

apps/console  tsc --noEmit                 -> exit 0
apps/console  eslint (新文件)              -> exit 0
node scripts/check-control-bytes.mjs       -> OK (scanned 3732 tracked text files)
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' (改动文件) -> 零命中
node scripts/check-changeset-presence.mjs  -> OK(1 released-package src file, 1 changeset)
node scripts/check-changeset-fixed.mjs     -> OK
node scripts/check-changeset-no-major.mjs  -> OK

Changeset

.changeset/registry-inputs-spec-parity-gate-3797.md,空 frontmatter。依据:scripts/check-changeset-presence.mjs 的守卫面是「fixed 组里每个包的 src/**」,@object-ui/consolefixed 里且住在 apps/console,该脚本头注明确写了「No carve-out for test files under src/ —— 限于 src/__tests__/** 的改动由空 frontmatter 豁免一行答完」。它要的是一句声明而不是一次发版:本 PR 没有任何发布行为或授权面变化(四个 block 的 inputs 未动),所以不声明任何包。已跑该脚本确认按空 frontmatter 通过。


关联


Generated by Claude Code

#3797)

把 PR #3795 在 `record:highlights` 上落的单块检查(「不得声明 spec 不接受的顶层
input」)推广到所有「`ComponentPropsMap` 有条目且本仓注册了非空 `inputs`」的 block,
期望值运行时从 spec 自身 shape 推导(不复述键表),现有偏离全部进**显式豁免名单**,
每条带理由 + 追踪单号。

门放在 `apps/console/src/__tests__/`,因为它需要的是产出发布物那份完整注册图:
`dev/manifest-dump.tsx` 用 `src/register-plugins.ts` + `@object-ui/components` 搭
manifest,本文件就导入这一对(与隔壁 `public-contract.test.ts` 同法),不自己攒一份
会自说自话的清单。覆盖面不限于 public tier —— `renderers/layout/page.tsx:462` 用
`getKnownTypes()` 现搭运行时 JSX 页面校验 manifest,所以非 public 的 block(如
`element:record_picker`)的 `inputs` 同样是活的 prop 白名单。

四个 OFF-SPEC block 逐块以代码判定,结论都落在 spec 一侧,因此**本仓四个 block 的
`inputs` 一个字节都没动**:

- `page:header` 的 `recordChrome`/`showStar`/`showCopyId` —— 渲染器实读
  (`containers.tsx:979/980/981`),消费于 `:1453` 的布局分支与 `:1531/:1532` 的
  RecordTitleChip;作者可达且非宿主注入(宿主注入走 RecordContext 且故意不声明),
  `preview-samples.ts:68` 与 `buildDefaultPageSchema.ts:413` 今天就在写。
  (issue 猜「可能是 #3226/PR #3265 有意保留的 renderer-only prop」已证否:#3265
  动的是 `packages/layout` 的遗留别名 `page-header`,canonical 这个没被碰过。)
- `page:accordion.variant` —— 渲染器实读 `containers.tsx:734`,`:735` 据此改每个
  面板的边框类,spec 完全没有对应键。
- `page:tabs.tabStyle` —— spec 已用 `type` 声明同一概念,所以是「一义两拼」;但两条
  本地动作都被证否:撤掉它会删掉扁平 SDUI 载体唯一能表达的拼法
  (`SchemaRenderer.tsx:251-270` 故意不上提 `properties.type`),改成发布 `type` 又
  会声明一个自家 parser 结构上无法校验的键(`validate.ts` 的 `BASE_PROPS` 含
  `'type'`)。收敛方向是 spec 侧的契约决定,不在这里猜。
- `element:record_picker` 的 `labelField`/`valueField`/`label` —— 上游
  objectstack#5775 已经解决,且正是往本仓渲染器实读的 `labelField` 收敛
  (`displayField`/`searchFields`/`multiple` 已转 `retiredKey()` 墓碑)。本仓这三条
  flag 纯粹是 pin 落后:npm 上最新已发布的 `@objectstack/spec` 是 `17.0.0-rc.5`,
  早于 #5775。

前三项转 objectstack#6776(跨仓转移协议,`pm:queue`,带 `Part of objectui#3797`);
八条豁免全部挂单号。豁免会自己过期:一旦 spec 声明了某个被豁免的键,
`carries no stale exemption` 就红,强制删条目,名单不会烂成永久 allowlist。

Fixes #3797
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 8, 2026 5:14pm

Request Review

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-D3crvStP.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 481.69KB 106.04KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 9.85KB 3.18KB
data-objectstack (index.js) 139.51KB 35.97KB
fields (index.js) 230.82KB 56.70KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 117.21KB 30.27KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.99KB 57.58KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.10KB 27.10KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 187.71KB 49.68KB
plugin-kanban (index.js) 48.30KB 13.28KB
plugin-list (index.js) 105.12KB 25.48KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

✅ 验收通过(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt)—— undraft + auto-merge。

git 实物核验(ffb823b82):净 diff 2 文件(+364,门本体 + 空 frontmatter changeset);豁免名单 8 条各带 file:line 证据与单号,「豁免过期即红」断言使 record_picker 三条在 pin 提升那一刻被机械强制清理 —— 豁免不是放行而是可审计的等待,这是门设计的正确形态。空 frontmatter 依据引的是判定脚本自己的头注(src/tests 豁免条款),CI Changeset Declaration 绿。

逐块判定全部采纳:四块结论均为「spec 补声明」方向、本仓 inputs 零字节改动 —— 与 #3226/#3265 误归因的证伪(那次动的是 packages/layout 遗留别名,canonical page:header 从未被收窄)和 record_picker 系 pin 落后(上游 #5775 已按本仓渲染器实读拼法收敛)两条子前提修正一致。跨仓移交合规:objectstack#6776 已立(pm:queue),page:tabs 的 type↔tabStyle 改名 vs 别名两案连代价写进上游单交 spec owner,不在本仓猜 —— 处置正确。

验证质量:四条反向验证先判后跑全吻合,RV2 的「探针没造对与断言不管用输出同形」自误披露是方法库级的诚实记录;「行为不回归为空项」如实声明而非编造(inputs 与渲染逻辑零改动,无可验面)。19 项 CI 全部完成 0 失败(PM 独立复核)。

衍生三单:#3807(record:details sections 教退役形状,#3407 同族)、#3808(反方向 15 键未发布,已按 A/B/C 预分类)另行判级;#3809(门的墓碑盲区,pin 升级即醒)为 finding 在案 —— pin 提升单执行时须连带处理。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 8, 2026 17:25
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit 5147d93 Aug 8, 2026
20 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3797-inputs-spec-parity branch August 8, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

registry inputs 与 spec ComponentPropsMap 之间没有 parity 门,4 个 block 发布了 pin 版 spec 不接受的顶层 input

2 participants