Skip to content

fix(plugin-list)!: a non-grid view's selection bar draws only actions the object declares (#30394) - #30498

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-2l6777
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-2l6777

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread
domain:ui#5 · os-sales · session_01L6bhgVzvtWN68zb2r9z2zy

Fixes #30394

Clause-②: yes (narrowing) — @object-ui/plugin-grid now exports resolveBulkActions and useUndeclaredActionNamesWarning (with the ActionLabelResolver, NamedActionDef, UndeclaredActionNameKey, UndeclaredActionNamesAddress and UndeclaredActionNamesBasis types), so @object-ui/plugin-list reuses the grid's fold and warning instead of a second copy. The warning's address gains an optional component, defaulting to ObjectGrid, so the grid's message is byte-identical. This PR both widens (those exports) and narrows (the non-grid bar no longer draws an undeclared bare name), so the arm is (narrowing): seat patch round on the Check Changeset red, after claim amendment 6658495307 had written (widening). Owes a TIER_DEFAULT review for the export widening and a CONTRACT_REVIEW_TIER review for the narrowing below.
Metadata-protocol: narrowed (an undeclared bare bulkActions name no longer draws in a non-grid view, matching #30387 on the grid)
Skills-docs: none owed — skills/** teaches no handler-only bulk action name (searched skills/ for bulkActions examples); content/docs/ui/** already names only declared actions.

维护者速读

  • 改了什么:看板、日历、画廊等非表格视图的选择栏,改成和表格同一条规则:视图 bulkActions 里的裸名字,只有对象声明了同名操作才画按钮,用声明的标签;删除照旧走自己的路径;没声明的名字不画,开发态控制台打一行警告点名。
  • 为什么改:A list's selection bar still draws a bulk action that a disabled package withholds, as a ghost button that toasts "not executable" #30169 裁决 C 后表格已不画未声明的操作(PR fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387),但切到看板等视图,勾选记录后仍会出现幽灵按钮(比如被禁用模块扣下的「Create Campaign」),点了只弹「不可执行」。
  • 风险与回滚:plugin-list 新增对 plugin-grid 的 peer 依赖(控制台 app-shell 本来就同时装两包);plugin-grid 入口多两个导出,警告消息多一个可选的组件名字段,表格输出不变。若仓外宿主靠前端接管一个未声明的名字,非表格视图里它的按钮会消失。回滚即 revert 本 PR。
  • 先看:ui/packages/plugin-list/src/ListView.tsx(nonGridBulkBar 折叠与选择栏渲染)→ ui/packages/plugin-grid/src/undeclaredActionNames.ts(可选 component)→ ui/packages/plugin-grid/src/index.tsx(两个新导出)。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.nonGridBulkDeclared-30394.test.tsx,预期 4 条全过;去掉折叠(消融)时其中 3 条转红。
  • 需要你做的:无,席位落地。

What changes

ListView draws its own selection bar for every view but the grid (kanban, calendar, gallery, timeline, …). That bar mapped each bulkActions member straight to a button labelled by the humanized name, declared or not. #30169 (ruling C, comment 6651753071) made the grid draw only actions the object declares; this applies the same rule to the other bar, through the grid's own code.

  • ListView.tsx. A new nonGridBulkBar memo folds permittedBulkActions (the existing delete gate is untouched) through plugin-grid's resolveBulkActions, with the canonical delete held out of the fold exactly as ObjectGrid holds it out. The bar draws, in authored order, delete (its own path, gate and per-record visibleWhen subset, unchanged) and each name the served object declares, under the declared label resolved through the app's i18n bundle (the grid's localizeLabel). Any other name draws nothing. A bar with nothing left to draw is not rendered. useUndeclaredActionNamesWarning names the undrawn names once in development, only while a non-grid view is on screen (the grid warns for itself) and only once the object schema read has settled; with no schema in hand (no getObjectSchema, or the read failed) the names are reported as unread, never as undeclared, the grid's reading.
  • plugin-grid/src/undeclaredActionNames.ts. UndeclaredActionNamesAddress gains an optional component that heads the message; omitted, it is ObjectGrid, so every grid message is byte-identical. ListView passes ListView and the view on screen as blockType: [ObjectUI] ListView bulkActions: kanban (objectName: 'lead') — 1 name matches no action the object declares, ….
  • plugin-grid/src/index.tsx. Exports resolveBulkActions, useUndeclaredActionNamesWarning and the types their signatures name.
  • plugin-list/package.json. Declares @object-ui/plugin-grid as a peer (workspace:^) and dev (workspace:*) dependency, following its @object-ui/plugin-detail precedent. No cycle: plugin-grid does not depend on plugin-list. plugin-list's build externalizes @object-ui/*, so its dist does not bundle the grid. pnpm-lock.yaml moves by the three lines that declaration adds.
  • Fixtures. ListView.bulkDeleteVisibleWhen.test.tsx and ListView.permissions.test.tsx used archive as their non-delete control without the object declaring it; both fixtures now declare { name: 'archive', label: 'Archive' }, so the control still draws (moved pins, assertions unchanged).

Why

Same defect as #30169, one more surface: after PR #30387 a list shown as a grid hides a name the object does not declare (for example an action a disabled package withholds), but the same list switched to kanban or gallery still drew a button for it, and pressing it toasted "not executable". The card asks for the grid's resolver to be reused rather than copied; plugin-list could not reach it (no dependency, not exported), measured and reported to the seat before plugin-grid was touched.

Tests

  • New ui/packages/plugin-list/src/__tests__/ListView.nonGridBulkDeclared-30394.test.tsx (gallery view, selection stubbed the way ListView.bulkDeleteVisibleWhen.test.tsx does): a declared name draws under its declared label and dispatches by name, delete draws in authored order, an undeclared name draws nothing and is named in one ListView warning; all-undeclared draws no bar; no getObjectSchema reports the names as unread; all-declared warns nothing.
  • ui/packages/plugin-grid/src/__tests__/undeclaredActionNames.test.ts: the message heads with ObjectGrid by default and with the address's component when given.

Acceptance notes

  • Importing the plugin-grid entry (sideEffects: true, it registers object-grid on import) did not disturb plugin-list's mocked registrations: the full plugin-list suite is green (below), which was the measured risk in the claim amendment's plan B.
  • The non-grid bar still dispatches through the host's onBulkAction(name, rows); promoted defs' params, confirm text and visible are not consulted on this bar (they never were). Unchanged by this PR.

Verification

Heads 38d91dbe and 4d680aaa change only the changeset over fbecf332: the Clause-② arm ((widening) → (narrowing)), then the summary's !; on it check-changeset-no-major (fed this body as the event) exits 0 where the (widening) body exits 1 with the level-axis contradiction, and check-adr-0087-registration, check-empty-changeset, check:changeset-fixed exit 0 on 4d680aaa. The (narrowing) arm owes the full dogfood battery on the final head; its reading goes to the seat. Everything below is on fbecf332 unless stated; the build closure was pnpm exec turbo run build --filter='@object-ui/plugin-list^...' (53/53 tasks).

Package suites and type-check
  • pnpm --filter @object-ui/plugin-list test on 85a03128 (the fix commit; fbecf332 changes only the changeset marker and the new test's spy typing): Test Files 190 passed (190), Tests 1817 passed (1817), lock VERDICT command-exit 0.
  • pnpm --filter @object-ui/plugin-grid test: Test Files 278 passed (278), Tests 2389 passed (2389), VERDICT command-exit 0.
  • pnpm exec vitest run packages/plugin-list/src/__tests__/ListView.nonGridBulkDeclared-30394.test.tsx: Tests 4 passed (4).
  • pnpm --filter @object-ui/plugin-grid --filter @object-ui/plugin-list run type-check: plugin-grid Done; plugin-list green after typing the new test's spy (fbecf332).
  • pnpm --dir ui run check:spec-symbols :: exit 0 (1807 files scanned against 5743 spec export names; ... 0 untriaged collisions).
Ablation (one, on the tested behaviour)

node scripts/ablation-replace.mjs --file ui/packages/plugin-list/src/ListView.tsx --anchor ".filter((a) => a.toLowerCase() === 'delete' || labels.has(a))" --replacement ".filter(() => true /* ABLATION-30394 */)" -- …vitest run …nonGridBulkDeclared-30394.test.tsx

  • Mutation landed: anchor 1 → 0, blob c5b3c47fb594 → 5ddccdf4efbb.
  • Mutated run: Tests 3 failed | 1 passed (4); the passing one is the all-declared control, which the mutation cannot move.
  • Restored: blob after restore c5b3c47fb594 == HEAD, git diff HEAD empty.
Derived gates (dispatch-gates --commands, 57 families)
  • 57 derived, 57 run, 0 NOT-MEASURED (--ran with an exit code on every line: "a DERIVED zero").
  • Two needed a second run: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 1 on 85a03128 (the narrowed kind requires a disposition), exit 0 on fbecf332 after the changeset gained not-required (no-migration-prescription); pnpm check:dual-build-cjs-loads :: exit 3 (PREREQUISITE NOT MET, dists missing) then exit 0 (116 published require entry point(s) across 71 package(s) load).
  • Changeset families re-run on fbecf332: check-changeset-no-major 0, check-empty-changeset 0, check:changeset-fixed 0, check-closing-keyword-parity 0.
  • Every other family exit 0. Families CI runs are read from this PR's check-runs.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: n/a.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English, except the 维护者速读 section the fleet requires.
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…the object declares

The bar ListView draws itself for kanban, calendar, gallery and the other
non-grid views mapped every bare `bulkActions` name to a button. It now
folds the names through plugin-grid's `resolveBulkActions`, the grid's own
fold: a declared name draws under its declared label, the built-in
`delete` keeps its own path, and any other name draws nothing and is named
once in development by plugin-grid's `useUndeclaredActionNamesWarning`.

plugin-grid exports the two (and their types) for this, and the warning's
address gains an optional `component`, defaulting to `ObjectGrid` so the
grid's message is unchanged. plugin-list declares plugin-grid as a peer
and dev dependency.

Co-Authored-By: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01L6bhgVzvtWN68zb2r9z2zy
@github-actions github-actions Bot added size/m dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@objectstack-fleet objectstack-fleet Bot changed the title fix(plugin-list): a non-grid view's selection bar draws only actions the object declares (#30394) fix(plugin-list)!: a non-grid view's selection bar draws only actions the object declares (#30394) Nov 5, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#5 · os-sales · session_01L6bhgVwQZbHRRM9CaXeKif

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 4d680aaabc35974ca9a375d21383118a811bd03a
Local-runs: none
Scope: ui/packages/plugin-list/src/ListView.tsx, ui/packages/plugin-grid/src/index.tsx, ui/packages/plugin-grid/src/undeclaredActionNames.ts, ui/packages/plugin-list/package.json + ui/packages/plugin-grid/src/resolveBulkActions.ts(resolveBulkActions、toBulkActionDef), ui/packages/plugin-grid/src/ObjectGrid.tsx(:814 objectName、:1255-1327 折叠、keptDeleteAction、objectSchemaAwaited 与两次警告调用), ui/packages/plugin-grid/src/components/BulkActionBar.tsx(:21-33 visible、:102 mayInvoke(requiredPermissions)), ui/packages/plugin-grid/package.json, ui/packages/plugin-list/vite.config.ts(:56 别名、:71 externalize), ui/packages/i18n/src/useObjectLabel.ts(:570、:806、:814 actionLabel 解析器), ui/packages/app-shell/package.json, ui/apps/console/package.json, ui/packages/plugin-map/package.json(plugin-list 的三个依赖方), packages/spec/src/ui/action.zod.ts(:1159-1162 name/label 必填), scripts/check-changeset-no-major.mjs(level 轴), .github/workflows/ci.yml(dogfood job 的 if:), .claude/agents/os-dev.md(DoD 的 dogfood 一行);diff 余量(.changeset/30394-non-grid-bulk-bar-declared-actions.md、pnpm-lock.yaml、四个测试文件)只为 ① 与 ② 读过,属车道席 TIER_DEFAULT 的 ACCEPT。

输入:卡 #30394 正文与全部评论(triage 6655193895、认领 6658430589、认领修正 6658495307 = plan A 裁定、os-dev-report 6659349029);PR #30387 正文、文件表与其达档复核 6654355327(点名本面为后续卡);PR #30498 正文、文件表、相对 main(merge-base 6c4c43ab9f)的净 diff(10 文件,+294/-12);head 4d680aaa 的 check-runs。⛔ 派工单与派工席自己的结论不是输入。复核于 2026-11-05T14:33Z。

① Derived judgments

逐条列 diff 蕴含的 accept-set 与公开面变化,各判对错:

  1. @object-ui/plugin-grid 入口新增两个运行时导出 resolveBulkActions、useUndeclaredActionNamesWarning 与五个类型导出(index.tsx :35-39、:63-68)。对:两个模块在 main 上已存在、只是入口未暴露(fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 复核 ① 第 7 条读到"NOT exported"),没有任何既有导出被改名或撤回;这是 plugin-grid 公开面的一次纯加宽。resetUndeclaredActionNamesWarnings 有意不导出(见 ④)。
  2. UndeclaredActionNamesAddress 增一个可选 component?: unknown,缺省读作 ObjectGrid(undeclaredActionNames.ts :49-55、describeComponent :79-81)。对且向后兼容:字段可选、与同级字段同样用 unknown 守型,ObjectGrid.tsx :1315-1319 自己的地址对象不写它,两条消息模板的头只改为 ${describeComponent(address.component)},缺省串与改前字面相同——表格的每条消息逐字节不变;useEffect 依赖数组同步加了 component。plugin-grid 测试新用例把两种头都钉住。
  3. 非表格视图的选择栏现在只画两类按钮:内建 delete(走自己的路径,仍先过 bulkDeleteVerdict → permittedBulkActions 的对象级门、再过每条记录的 bulkDeleteEligibility,两处都未动)和对象声明过的名字(经 resolveBulkActions 对 objectDef.actions 折叠,标签取声明的 label 并经 useObjectLabel().actionLabel 走 i18n)。未声明的名字不画;无东西可画时整条栏不渲染(ListView.tsx :2554-2570、:7401、:7413-7439)。对:这正是 A list's selection bar still draws a bulk action that a disabled package withholds, as a ghost button that toasts "not executable" #30169 裁决 C 的第一句,也是卡 Console list views other than the grid (kanban, calendar, gallery…) still draw every bare bulkActions name as a selection-bar button, declared or not, after #30169 #30394 的 Expected("a bare name draws only when the served object declares an action of that name (promoted with its label), delete keeps its own path")。delete 的排除与保留都按 toLowerCase(),与 ObjectGrid.tsx :1266、:1292 同一写法。
  4. 派发不变:按钮仍 props.onBulkAction?.(name, rows)(:7433)。对——卡的 Expected 不要求改派发,fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 的复核已把该栏"派发到哪里"判为另一张裁决;相关缺口见 ③ 第 2 条。
  5. 开发态警告:ready: objectDefLoaded && currentView !== 'grid'、basis 在 schema.objectName && objectDef == null 时为 unread、地址 { component: 'ListView', blockType: currentView, objectName, label }(:2576-2582)。对:objectDefLoaded 在四条路径上都会置真(无 dataSource/objectName、无 getObjectSchema、读成功、读失败的 finally,:2826-2856),与表格的 !objectSchemaAwaited(ObjectGrid.tsx :1311-1313)同义;unread 的判法与 :1314 同形。表格视图上保持沉默、由 ObjectGrid 自报,切到看板后由 ListView 报一次——同一张列表两种视图各一条消息,内容按 component/blockType 不同,不是重复。
  6. plugin-list 新增 @object-ui/plugin-grid 的 peer workspace:^ 与 dev workspace:*。对:照 @object-ui/plugin-detail 的既有写法;对 ui/packages/* 与 ui/apps/* 全部清单做可达性检查,plugin-grid 与 plugin-detail 都到不了 plugin-list,无环;vite.config.ts :71 把所有裸 id 外置、:56 的 @object-ui/plugin-grid → ../plugin-grid/src 别名本就存在(本 PR 是它第一次被源码用到);锁文件只多 dev link 三行。依赖方三个:app-shell、console 本已声明 plugin-grid;plugin-map 只在 devDependencies 里拉 plugin-list 给三个测试用,靠 pnpm 的 peer 自动安装与 plugin-list 自己的 node_modules 解析,Validate Package Dependencies 与 Type Check UI 绿。一个后果要点名:仓外宿主若只装 plugin-list,现在会缺 peer——由 (narrowing) 臂覆盖,但 changeset 正文没写(② 的 should-fix)。
  7. 两个 fixture 改为声明 archive(bulkDeleteVisibleWhen、permissions 两测试):移动 pin、断言不变。对。
  8. hook 次序:新 useUndeclaredActionNamesWarning 在 :2576,组件体第一个顶层 return 在 :6202,之前无提前返回;nonGridBulkBar 的 memo 依赖(permittedBulkActions、objectDef、schema.objectName、resolveActionLabel)齐全。对。

② Semver level

  • changeset '@object-ui/plugin-list': minor、'@object-ui/plugin-grid': minor。level 轴只问 Metadata-protocol: 的种类:narrowed ⇒ 至少一个被 diff 移动的包 minor 以上;两个包都被移动(plugin-grid 加导出与消息字段,plugin-list 改行为),两个 minor 与门的规则一致;(narrowing) 在发布窗口期按 minor 出(check-changeset-no-major.mjs :1839)。匹配。
  • Clause-②: yes (narrowing):yes 对应 plugin-grid 公开面加宽(① 第 1 条),(narrowing) 臂对应 plugin-list 接受集收窄(① 第 3 条);门的规则 narrowed 不能坐在无 (narrowing) 臂的行旁(:2048),所以认领修正里的 yes (widening) 恰是那条矛盾,席位补丁轮改成 (narrowing) 是对的;标题与 changeset 摘要的 ! 是该臂要求的 BREAKING 横幅。ADR-0087 处置标记 not-required (no-migration-prescription) 在 changeset 正文内、理由成立(无键、导出或存储行变形)。PR 正文与 changeset 两处行首声明一致。Check Changeset(两次)、Lint & Repo Gates 在本 head 绿。
  • Metadata-protocol: narrowed:spec 文本未动,但作者写下的裸名字在又一个面上被收回到 spec 自己的那句话——与 fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 复核 ② 的读法相同,保守读为"要求收紧"。接受。Skills-docs: no move 与本复核所读一致。无 packages/spec 改动,不欠生成物。
  • should-fix(②-a):changeset 的 Before/Now/Remedy 写了新导出与行为变化,没写 @object-ui/plugin-list 对 @object-ui/plugin-grid 的新 peer 依赖;仓外只装 plugin-list 的宿主升级后先碰到的是缺 peer,不是行为变化。Remedy 加一行"同时安装 @object-ui/plugin-grid"即可。散文,不构成 FAIL。

③ Boundary flags

os-dev-report 6659349029 与认领修正 6658495307 的每面旗:

  1. open_questions: []——无待答。
  2. out_of_scope_findings 第 1 条(非表格栏按名派发,不读提升 def 的 params / confirmText / visible;"carrier: none · 记在 Acceptance notes,未立卡")。在树上确认:表格栏 BulkActionBar.tsx :102 过 mayInvoke(requiredPermissions)、:21-33 逐记录算 visible;非表格栏现在手里已有折叠出的 def(resolveBulkActions 返回的 def 带 requiredPermissions 与 visible),却只取 label 丢掉其余。判:先于本 PR 存在、在卡 Expected("promoted with its label")之外、fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 复核已把该栏的派发判为另一张裁决——should-fix,作后续卡;但按 Prime Directive chore: version packages #10,行内菜单遵守而选择栏不遵守的能力门(ADR-0066 D4"the capability gate travels with the action")是可复现的契约缺口,须由席位立卡,不能只留在 Acceptance notes。不是本 PR 的 must-fix。
  3. dogfood_battery: "n/a — no ! in the PR title and Clause-② carries the (widening) arm"——已过时:写报告时臂是 (widening)、标题无 !;终 head 4d680aaa 标题带 !、臂为 (narrowing),按 .claude/agents/os-dev.md DoD("全量 dogfood 只在终 head 跑一次,仅当标题带 ! 或 Clause-②: 带 (narrowing) 臂")全量电池应在终 head 跑。PR 正文把这一读数"交给席位"。CI 不能代答:ci.yml 的 dogfood job if: 排除 pull_request 与 merge_group,本 head 上"Dogfood Regression Gate" 的 success 是聚合器对两条被跳过腿的记账,Dogfood Regression Gate (shard/3) 与 Dogfood Verify CLI 都是 skipped。影响面:@objectstack/dogfood(packages/qa/dogfood)不 import 任何 @object-ui/*,两处提到 console 的文件读的是 packages/console 的 dist,本 diff 不动它(无 console:build),电池对本 diff 在构造上不可见。上报席位:入队前由席位记录该电池在终 head 的读数(或记录"按可达性不可见"的裁定);本复核只读,未跑。不是树的缺陷,不改判。
  4. Plan B(旁路子路径导出)未启用:开发者测得导入 sideEffects: true 的 plugin-grid 入口不干扰 plugin-list 的 mock 注册(全套 190 文件绿);CI Test UI 16 分片在本 head 全绿(见下)。接受。
  5. 认领修正"⛔ ObjectGrid.tsx stays out":文件表无该文件,守住。
  6. 认领修正"两面都欠复核:narrowing 在 CONTRACT_REVIEW_TIER、export widening 在 TIER_DEFAULT":本记录是前者;后者(导出加宽与 diff 余量)是车道席的 ACCEPT。
  7. PR-body guards 在本 head 上一次 cancelled、一次 success——同一 head 因正文编辑重跑,后者为准,读作绿。

④ Design judgment

逐 hits 文件,对着引用的代码与接受它的场景(#30394 裁定 plan A、#30387 表格行为)判,每次破坏尝试都写出:

  • ui/packages/plugin-list/src/ListView.tsx — 成立。
    • 对象恰好声明了一个名为 delete 的操作:先于折叠被剔出、按内建路径画,和 ObjectGrid.tsx :1266 一样,不会被报为未声明。
    • 看板 / 日历 / 画廊 / 时间线 / 甘特 / 地图 / 树 / 图表:选择栏是同一个 currentView !== 'grid' 块(:7401),所以由构造全部覆盖;树与图表没有选择,栏不出现,警告仍在开发态报一次(名字无论视图都未声明),无害。
    • 视图切换 grid → kanban:memo 不依赖 currentView,栏的渲染条件与警告的 ready 依赖它;切换后折叠结果复用、栏出现、警告首次触发。成立。
    • 未声明名字 + 无 getObjectSchema 的数据源:objectDefLoaded 置真、objectDef 为 null ⇒ unread,名字不画但说"未读到",不说"未声明";delete 照画(新测试第 3 条钉住)。与表格同读。
    • schema.label 为 { en, zh } 映射时:describeAddress 的 typeof string 守卫把它丢掉,与表格同。
    • should-fix(④-a,nit):drawn 对未去重的 names 映射(:2566-2568),bulkActions: ['archive', 'archive'] 画两个同 React key 的按钮;改前的 permittedBulkActions.map 也如此,不是本 PR 引入,但表格那侧由 resolveBulkActions 的 claimed 去重了。用 labels 之外再记一个 seen 集合即可。
    • 观察(不计):声明的操作若 label 是 I18n 映射而非字符串,toBulkActionDef 丢掉映射、localize(name, name) 回落为裸名字 qualify_lead,比改前的 formatActionLabel 标题化少了一层美化;表格同一折叠、同一结果,本卡要的就是和表格一致,且 spec ActionSchema.label 必填、常见写法是字符串。
    • 观察(不计):bulk-skipped-notice 的条件改读 drawn,delete 只要被允许就必在 drawn 里,等价。
  • ui/packages/plugin-grid/src/index.tsx — 成立。两个值导出、五个类型导出,与模块签名引用的类型一一对应,无多无少;注释说明"One rule, one copy"。resetUndeclaredActionNamesWarnings 不导出:plugin-list 的新测试用四个不同 objectName 绕开 warn-once 记忆,可行;若将来 plugin-list 的测试需要重置,没有把手——测试层 nit,不计。
  • ui/packages/plugin-grid/src/undeclaredActionNames.ts — 成立。可选字段、缺省值、unknown 守型、依赖数组、测试钉——四样齐。fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 复核的四条 should-fix 在树上都已落地((a)(b) objectSchemaAwaited 按解析后的 objectName 判;(c) 字面量 process.env.NODE_ENV;(d) warnedMessages 记忆),ListView 复用即全部继承。
    • should-fix(④-b,散文):unread 分支的处方仍写 "Give the grid a data source that answers getObjectSchema"(:111);ListView 的消息里这个 "grid" 是错词,改成 ${describeComponent(address.component)} 或 "the component" 一词即可。
  • ui/packages/plugin-list/package.json — 成立。peer workspace:^ + dev workspace:* 照 plugin-detail 先例;无环(① 第 6 条);dist 不打包 plugin-grid;Validate Package Dependencies 绿。观察(不计):UMD 的 globals 表既没写 plugin-detail 也没写 plugin-grid,rollup 会猜一个全局名——plugin-detail 已是这形状,check:dual-build-cjs-loads 在闭包构建后 exit 0(开发者报告)。
  • 对着 main 上已发布的 spec:这次收窄让 spec 自己的那句话(bulk-action.zod.ts 的 "names an action the object declares")与 lint action-name-undefined 在又一个消费端成真,没有拿走任何已声明的能力:无键、无值、无导出变形。成立。

无 must-fix。should-fix 三条(②-a、④-a、④-b)各是一两行,不阻塞落地;③ 第 2 条由席位立卡,③ 第 3 条由席位记录读数。若在本分支上补这些再推,新 head 另欠一张记录。

本 head 的 check-runs(其结论即门的判决,读于本记录写成时):Type Check UI、TypeScript Type Check、Type Check · workspace / source gates / consumer gates / debt ledger、Build UI Deps、Build & E2E UI、Live E2E UI、Lint UI、Lint & Repo Gates、Lint · ESLint / PM dispatch-gates / docs & code guards / repo & tooling gates / CI, release & engine gates / scoped ×3、Check Changeset(×2)、Governed Surface Queue Guard、Validate Package Dependencies、Build Core、Build Docs、Test Core、Plan Test Core shards、Dogfood Regression Gate(聚合器,两腿 skipped,见 ③ 第 3 条)、Check PR Size、Auto Label、PR-body guards(success;同 head 另一次 cancelled 为被取代的早跑)、Test UI 全部 16 分片——每一项都 success(49 success、0 failure);path-skipped:Test Core (shard/8)、Dogfood Regression Gate (shard/3)、Dogfood Verify CLI、Temporal Conformance、UI Published Artifacts、18.x upgrade harness、Packed-tarball smoke、Schedule gate。本 head 上没有一个红的 check-run。

Implemented-by: claude/project-thread-2l6777
Reviewed-by: session_01L6bhgVwQZbHRRM9CaXeKif

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#5 · os-sales · session_01L6bhgVwQZbHRRM9CaXeKif

维护者速读

席位核对 — ACCEPT · domain:ui#5 · head 4d680aaabc35974ca9a375d21383118a811bd03a

  • 形态: draft,作者 objectstack-fleet[bot](中继 pr_create),目标 main,Fixes #30394。共 10 个文件,+294 −12。check-governed-merges --pr 30498:NOT governed;306 行,未超 3000。mergeable_state 读为 clean。
  • 契约面: 不碰 packages/spec/**,不碰 governed 路径。Clause-②: yes (narrowing)、Metadata-protocol: narrowed、Skills-docs: none owed,标题和 changeset 摘要带 !,两个包 minor。CONTRACT_REVIEW_TIER 合同复核 PASS 6660632027(fable),复核的就是这个 head。plugin-grid 入口的导出放宽在该记录 ① 第 1 条里判过,席位按 TIER_DEFAULT 认同:只新增导出,没有改名或撤回。
  • 补丁轮: 第一版 head fbecf332 在 Check Changeset 红,原因是 narrowed 旁边写了 yes (widening)。席位补丁轮改为 yes (narrowing),再按 fix(plugin-grid)!: a list's selection bar and row menu draw only actions the object declares (#30169) #30387 先例给标题和 changeset 摘要加 !。4d680aaa 相对 fbecf332 只改了 changeset 一个文件。
  • 门禁 check-runs: 4d680aaa 上 60 个 run:49 success,10 skipped,1 cancelled(PR-body guards 因正文编辑重跑,同 head 另一次 success)。Test UI 16 个分片全绿。
  • 全量 dogfood: 复核 ③ 第 3 条指出 CI 不跑 dogfood 腿(dogfood job 的 if: 排除 pull_request 和 merge_group),(narrowing) 臂要求终 head 跑全量。卡线程跑了 pnpm --filter @objectstack/dogfood test(不分片、不传路径):VERDICT command-exit 0,Test Files 419 passed / 3 skipped,Tests 3492 passed / 36 skipped,0 失败。跑在 38d91dbe 的树上,它和终 head 只差 .changeset 文件,dogfood 不读它。另外 packages/qa/dogfood 不 import 任何 @object-ui/*,本 diff 对它在构造上不可见。
  • 测试: 新增 ListView.nonGridBulkDeclared-30394.test.tsx,plugin-grid 测试钉住两种消息头;两个旧测试的 fixture 改为声明 archive,断言不变。卡线程报告:plugin-list 全套 190 个文件绿。
  • 接受的偏差:
  • 范围外去向: 非表格选择栏拿到了声明的操作定义,却没有用上 requiredPermissions 和 visible 两道门(表格栏 BulkActionBar.tsx:102、:21-33 都检查)。改动前就存在,不在本卡要求内,但属于 ADR-0066 D4 的契约缺口。席位已立卡 List views other than the grid: the selection bar draws a declared bulk action without its requiredPermissions or visible gate #30535。
  • 落地条款: Fixes #30394。本席位按普通队列在这个 head 上落地:relay pr_ready + automerge_enable。MERGED 后核对 Console list views other than the grid (kanban, calendar, gallery…) still draw every bare bulkActions name as a selection-bar button, declared or not, after #30169 #30394 已关闭、pm:dispatched 已摘。

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

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant