Skip to content

fix(fields): 退役 capability-multiselect widget 名 —— 删注册面与最后一个 hint 消费方,组件保留 (#3308) - #3793

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3308-capability-multiselect-retire
Aug 8, 2026
Merged

fix(fields): 退役 capability-multiselect widget 名 —— 删注册面与最后一个 hint 消费方,组件保留 (#3308)#3793
yinlianghui merged 1 commit into
mainfrom
claude/issue-3308-capability-multiselect-retire

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3308

按 2026-08-06 维护者裁决(该死 —— 删除,ADR-0049 enforce-or-remove)落地。核验后裁决三条里第 1、3 条按裁决执行,第 2 条的前提被证伪,原因与证据见下,未强推。

裁决逐条落实

1. 删 capability-multiselect 组件与承诺不存在能力的注释 —— 已删,但删的是 widget 名而非组件文件

前提复核(origin/main = 00b9451d8)确认 issue 的注册表事实成立:field:capability-multiselect 只由 registerFields() 注册,该函数唯一调用方是文档站,所以键从未存在于活路径(registerAllFields(),模块加载即执行,遍历 fieldWidgetMap —— 表里没有它)。

但引用面扫描发现 issue 未列的两个直接 import 消费方,组件本身并没有死:

  • packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx:72,788 —— Studio 权限矩阵编辑器直接 import 并渲染它(不经注册表),而且在活跃维护中(就地注释引用 objectui#3332 的 chip wall 高度修复)。这正是 ADR-0056 P2 的设计:"能力编辑器本身位于 Studio"。
  • packages/plugin-detail/src/InlineFieldInput.tsx:108 —— 也直接 import,在 widget === 'capability-multiselect' 分支里渲染。

所以字面执行"删组件"会打掉一个活的 Studio 编辑器。真正死的是 widget 名:注册面 + hint 分支。裁决意图(退役这个不可达的 field widget)完整保留,删除面为:

位置 删了什么
packages/fields/src/index.tsx field:capability-multiselect 注册 + 那段承诺注释 + 已无用的静态 import
packages/plugin-detail/src/InlineFieldInput.tsx widget === 'capability-multiselect' 分支(该 hint 最后一个 honoring surface)+ import
packages/components/src/renderers/form/form.tsx:234 DATA_SOURCE_FIELD_TYPES 里的死条目(永远匹配不到可解析 widget)
packages/plugin-form/src/ObjectForm.tsx:585 注释里把它说成 stamp 到 system_permissions —— 改为实际 stamp 的 permission-facet-link

CapabilityMultiSelectField 组件不动、仍从 @object-ui/fields 导出,doc 注释改为如实写明"它不是注册表 field widget"。

没有任何生产方 stamp 过这个 hint —— 这条是删 InlineFieldInput 分支的依据。packages/data-objectstack/src/index.ts:2486-2501(applyFieldWidgetOverrides,ADR-0056 P1 的单一 choke point)给 sys_permission_set 六个 facet(含 system_permissions)stamp 的是 permission-facet-link。全仓 + framework 仓零命中 stamp 处。留一个特例给无人 emit、无表单能解析的名字,正是本 issue 要消灭的声明/实际背离,只是方向相反。

2. 收敛 registerFields() 废弃路径、文档站改走 registerAllFields() —— 前提证伪,未执行

裁决(与 issue)把 registerFields() 当成"废弃的重复注册路径"。它不是。它是文档站的 demo host adapter,以注册表覆写的形式实现:

  • registerAllFields() 注册 withFieldCarrier(lazy(widget)) —— 裸 widget,只渲染控件。label / description / value 状态归 host(表单渲染器、FieldEditWidget、action dialog)。
  • registerFields() 注册 createFieldRenderer(widget) —— 额外合成 label、description 和本地 useState + onChange

正是这套 chrome 让裸字段节点能被 SchemaRenderer 独立渲染,而这就是文档站 demo 每一个 content/docs/fields/*.mdx 例子的方式:apps/site/app/components/InteractiveDemo.tsxrender 一个 SchemaRenderer,自己不传 value/onChange;examples/schema-catalog 里的例子形如 { "type": "currency", "name": "amount", "label": "Amount", "placeholder": "$0.00" }

实测(一次性 probe,未入 commit):按 demo 路径渲染 withFieldCarrier(CurrencyField),只给 schema 派生的 props 而不给 value/onChange——

PROBE onChange throw = null
stderr: TypeError: onChange is not a function
    at onChange (packages/fields/src/widgets/CurrencyField.tsx:79:11)

FieldWidgetComponentProps.onChange必填(widgets/types.ts:122)且 widget 无保护地调用它。方向值得如实记录:错误确实抛出,但发生在 React 事件系统内部,fireEvent 不会同步 rethrow —— 浏览器里的表现是 demo 输入框失灵 + 每次击键一条未捕获错误,而非组件崩溃边界。同时 label chrome 消失(queryByText('Amount') 为 null)。受影响面是 content/docs/fields/ 下 26 个字段文档页里走裸键的约 24 个类别。

所以"文档站改走 registerAllFields()"不是一次等价替换,它需要先决定 demo chrome 归谁。这一条留给维护者,本 PR 不猜。作为替代,本 PR 把引发误读的那句声明就地改对:@deprecated Use registerAllFields() instead 改写为如实说明两者不可互换、为什么文档站不能直接切、以及退役门槛,并注明 apps 一律用 registerAllFields()。选项与建议见文末。

裁决里预设的 semver 冲突点因此没有发生:registerFields 导出保留,没有公开导出被删,check-changeset-no-major.mjs 无需对抗。apps/site 一行未改(ObjectUIProvider.tsx 未动),emitted dts 里 export declare function registerFields(): void; 仍在,故文档站编译面无风险。

3. 存量引用留 tombstone —— 已留

四处删除点各有一段 tombstone 注释,写明:键曾在哪里、为什么死、谁 stamp 的是什么、组件为何还活着、以及"不要重新加回来"。CHANGELOG 里的历史提及按退役纪律原样保留,未改。

引用面扫描

origin/main = 00b9451d8。词界扫描防 registerAllFields 子串误命中。

git grep -n "capability-multiselect" origin/main —— 11 命中:4 处历史 CHANGELOG(不动)、1 处注册 + 1 处注释(删)、1 处组件 doc 注释(改写)、plugin-detail hint 分支(删)、components 死条目(删)、plugin-form 注释(改)。

git grep -nw "registerFields" origin/main —— 3 命中:定义 1 处 + apps/site/app/components/ObjectUIProvider.tsx:5,13。issue 所列的消费方完整。

跨仓:git -C /home/user/objectstack grep -nw "capability-multiselect" origin/main 唯一命中是 packages/spec/liveness/field.json:109 的一条 liveness note,把该 widget 记作 sys_permission_set 在用 —— 那条记录已陈旧(实际 stamp 的是 permission-facet-link)。属 framework 仓文档面、非本 PR 范围,已作为 observation-class finding 记入报告交 PM。

改后 git grep --untracked -n "capability-multiselect" 仅剩 tombstone / pin test / changeset / 历史 CHANGELOG。

semver 与 changeset 依据

minor,四个包(fields / plugin-detail / components / plugin-form)。依据 AGENTS.md「版本号策略」:objectui 的 major 跟随 @objectstack 节奏,fixed 组(39 包)任一 major 都会把全组推上去,因此自身破坏性变更也标 minor,破坏语义写在正文 —— 这是仓内明写的约定,不是偷偷降档。scripts/check-changeset-no-major.mjs 已跑,通过。

破坏性实际范围:仅"名字层面"。field:capability-multiselect 在文档站以外不可达,没有应用能解析到它;仍带该 hint 的字段现在退化为其声明的 type 渲染器,即未注册 widget 的既定行为(framework liveness note 原文:"Degrades to the type renderer when the widget is unregistered")。没有公开导出被删。

验证证据

引用面扫描见上。测试与门禁:

pnpm vitest run packages/fields                       -> 65 files | 978 tests passed
pnpm vitest run packages/plugin-detail packages/plugin-form
                                                      -> 88 files | 785 tests passed
pnpm vitest run packages/components                   -> 95 files | 698 tests passed
pnpm vitest run packages/app-shell/.../PermissionMatrixEditor
                                                      ->  7 files |  25 tests passed

type-check(fields / plugin-detail / plugin-form / components)全 Done;app-shell type-check 全绿(它是组件的直接消费方)。四包 buildDone。四包 lint 0 errors(warnings 是仓库既有基线)。

首轮 plugin-form type-check 报 9 条 TS2307 Cannot find module '@object-ui/fields' —— 新 worktree 未建依赖产物所致(AGENTS.md §9 陷阱),pnpm --filter '@object-ui/plugin-form^...' --filter '@object-ui/plugin-detail^...' build 后全绿,非本改动引起。

注册行为自证(packages/fields/src/__tests__/capability-multiselect-retired.test.ts):import '@object-ui/fields'ComponentRegistry.get('field:capability-multiselect') 与裸键均为 undefined; registerFields()(文档站路径)跑完后仍为 undefined;同时逐条断言该路径其余 38 个键全部仍注册 —— 退役恰好减一个名字,没有顺手削薄文档站路径。

反向自证:把删掉的两处肢体加回,两个 pin 按预期变红 —— fields pin 第 77 行拿到 [Function FieldCarrierAdapter](期望 undefined),InlineFieldInput pin 渲染出 2 个 chip button(期望 0)。值得单独记一笔:fields pin 的第一条(只看活路径)在肢体加回后仍然绿 —— 只钉活路径的测试在 origin/main 上就会通过、什么也钉不住,所以 pin 显式覆盖了文档站路径。变异未入 commit。

字节纪律:pnpm check:control-bytes OK(3718 tracked text files);改动文件另做一次 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 自扫,零控制字节。

content/docs/releases/** 未触。

待裁决:registerFields() 的最终归属(裁决第 2 条)

三个选项,按「本项目长期健康」与「让 AI 写的元数据难写错」两轴评估:

  • A. demo adapter 下沉到 apps/site —— 从 @object-ui/fields 删掉 registerFields + createFieldRenderer,文档站自己拥有一个 demo 包装器。库侧只剩一条路,文档不坏。代价:第二个包装器仍然存在(只是换了归属),文档 demo 仍渲染出真实应用不会产生的样子,"文档是错误权威"这个失效类没被消掉 —— 而这恰是本 issue 的病根。
  • B. 把 fields-* catalog 例子改成表单托管({ "type": "form", "fields": [...] }),两个包装器都删掉。文档从此展示真实应用的渲染结果(真表单渲染器拥有 label 与状态)。代价:约 60 个 catalog JSON + 26 个文档页要重验,PR 体量大,且改变了文档教什么,应当是维护者决定并单开一单。
  • C. 保留现状,只把声明改对(本 PR 已做的部分)。最省;但两路并存会继续长出漂移,即 capability-multiselect widget 在实际注册路径上根本不存在 —— 代码注释却说它可从记录表单用 #3308 发现的东西。

建议 B,单开一单;不建议 A。 两轴同向:长期健康上,A 是 patch —— 它把"文档 demo 与真实渲染不一致"这个二元契约原样保留下来,只换了持有者;B 消灭它。对"让 AI 写的元数据难写错"这一轴,差别更大:模型读文档看到裸字段节点渲染成带 label 的输入框,就会生成同样的裸节点,而在真实应用里它渲染不出 label、也没有 host 提供 onChange —— 文档正在充当一份错误权威,与本 issue 抱怨的注释是同一类缺陷。B 让文档只能展示真实可行的写法。本 PR 已按 C 把误导性声明改对,作为 B 落地前的安全垫。


Generated by Claude Code

…,组件保留

`field:capability-multiselect` 只由 `registerFields()` 注册,而该函数唯一调用方
是文档站,所以这个键从未存在于活路径(`registerAllFields()`,模块加载即执行,
遍历 `fieldWidgetMap` —— 表里没有它)。作者在字段上写
`widget: 'capability-multiselect'`,在文档站以外的任何应用里都解析不到组件,而
注册处上方的注释把它描述成可从记录表单使用的 widget:注释承诺了一个不存在的能力。

也没有任何生产方 stamp 这个 hint。ADR-0056 P1 经
`ObjectStackAdapter.getObjectSchema` 这一个 choke point,给
`sys_permission_set` 六个 facet(含 `system_permissions`)stamp 的是
`permission-facet-link`;P2 把能力编辑器放进了 Studio。该 widget 名是那次分期
落地中间态的残留。

按 ADR-0049 enforce-or-remove 删除,四处各留 tombstone:

- `fields` —— `field:capability-multiselect` 注册与那段注释。语义上是
  breaking,但仅止于名字:该键在文档站以外不可达,没有应用能解析到它。仍带该
  hint 的字段现在退化为其声明的 `type` 渲染器,即未注册 widget 的既定行为。
- `plugin-detail` —— `InlineFieldInput` 的 `widget === 'capability-multiselect'`
  分支,该 hint 最后一个 honoring surface。给一个无人 emit、无表单能解析的名字
  留一个特例,正是本 issue 要消灭的声明/实际背离,只是方向相反。相邻的
  `permission-facet-link` 分支未动,并新增断言钉住。
- `components` —— 表单渲染器 `DATA_SOURCE_FIELD_TYPES` 里那条死条目,它永远
  匹配不到一个可解析的 widget。
- `plugin-form` —— 一处把 `capability-multiselect` 说成 stamp 到
  `sys_permission_set.system_permissions` 的注释,改为实际 stamp 的
  `permission-facet-link`。

`CapabilityMultiSelectField` 组件本身不动、仍然导出:Studio 的
`PermissionMatrixEditor` 直接 import 渲染它,这就是 ADR-0056 P2 的设计。只退役
widget 名;组件的 doc 注释现在如实写明它不是注册表 field widget。

`registerFields()` 一并保留,但把 `@deprecated Use registerAllFields() instead`
这句改写为如实说明:两者不可互换 —— 它注册的是 `createFieldRenderer(widget)`,
额外合成 label、description 与本地 `value`/`onChange` 状态,正是这套 chrome 让
裸字段节点(`{ type: 'currency', label: 'Amount' }`)能在文档站 demo 里独立渲染。
实测:改走 `registerAllFields()` 后 `FieldWidgetComponentProps.onChange` 是必填
且 widget 无保护地调用它,demo 输入框每次击键抛
`TypeError: onChange is not a function`(CurrencyField.tsx:79)。退役它需要先决定
demo chrome 的归属,故留给 #3308 的后续裁决,注释就地记录,不再暗示是 drop-in
替换。

## 验证

- 引用面扫描(`origin/main` = 00b9451):`git grep -n "capability-multiselect"`
  改后仅剩 tombstone/pin-test/changeset 与历史 CHANGELOG。
- `pnpm vitest run packages/fields`:65 files / 978 tests passed。
- `pnpm vitest run packages/plugin-detail packages/plugin-form`:88 / 785 passed。
- `pnpm vitest run packages/components`:95 / 698 passed。
- `pnpm vitest run packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor`:
  7 / 25 passed —— Studio 侧组件消费方未受影响。
- 四包 `type-check` 与 `build` 全绿;`app-shell` `type-check` 全绿(它直接
  import 该组件);四包 `lint` 0 errors。
- 反向自证:把删掉的两处肢体加回,两个 pin 测试按预期变红
  (`field:capability-multiselect` 返回 FieldCarrierAdapter;inline 分支渲染出 2
  个 chip button)。值得记录的是 fields pin 的第一条(只看活路径)在肢体加回后
  仍然绿 —— 只钉活路径的测试在 `origin/main` 上就会通过、什么也钉不住,故 pin
  显式覆盖文档站路径。变异不入 commit。
- `pnpm check:control-bytes` OK;改动文件另做
  `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]'` 自扫,零控制字节。
- `node scripts/check-changeset-no-major.mjs` 通过(changeset 标 minor,按
  AGENTS.md 版本号策略:fixed 组不声明 major,破坏性语义写在正文)。

Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt

Co-authored-by: Claude <noreply@anthropic.com>
@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 4:20pm

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-CafLOlx3.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) 482.20KB 106.20KB
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.09KB 42.72KB
plugin-dashboard (index.js) 117.06KB 30.24KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.64KB 57.40KB
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。

裁决落实方式的裁定:裁决两条各有一处前提被 dev 实测证伪 —— (1)「删组件」:CapabilityMultiSelectField 被 Studio PermissionMatrixEditor.tsx:72,788 活消费(ADR-0056 P2 设计),字面删会打掉活编辑器;(2)「registerFields 废弃路径收敛」:它实为文档站 demo host adapter(合成 label + value/onChange),直切 registerAllFields 会让 ~26 页文档中约 24 类交互 demo 每击键抛 TypeError(dev 一次性 probe 实证)。dev 执行裁决本体(该 widget 名该死 → 名字已死)而非字面机制,PM 采纳 —— 与 #3460 同一处理先例。裁决第 2 条的终局形态(A/B/C,dev 荐 B)另立决策单交维护者,本 PR 已落地的「声明改对」作为安全垫不阻塞。

git 实物核验(56ea975a8):四处退役面各留 tombstone;组件文件保留且 doc 注释改为如实;app-shell 零改动(消费方不受影响,定向 25 测试绿);两个 pin 测试的反向验证方向先判后跑吻合,且 dev 发现「只钉活路径的 pin 在 main 上就绿、什么也钉不住」并显式覆盖文档站路径 —— 这条判据已写进测试头注,方法库入账。19 项 CI 全部完成 0 失败;changeset 四包 minor 依据 AGENTS.md fixed-group 版本策略,Bump Policy 门禁绿,非降档。

衍生:objectstack#6773(liveness 账本失真用例)、objectui#3794(ADR-0056 Consequences 自相矛盾)两条 finding 立单边界正确,归分诊席。


Generated by Claude Code

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.

capability-multiselect widget 在实际注册路径上根本不存在 —— 代码注释却说它可从记录表单用

2 participants