Skip to content

fix(components,plugin-detail): element:text.content / element:button.label 声明真实联合,第 6、7 个标本停止对合法写入告警 (#4970) - #4999

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-4970-elements-i18n-arms
Aug 17, 2026
Merged

fix(components,plugin-detail): element:text.content / element:button.label 声明真实联合,第 6、7 个标本停止对合法写入告警 (#4970)#4999
yinlianghui merged 2 commits into
mainfrom
claude/issue-4970-elements-i18n-arms

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #4970

#3832 的机制已随 PR #4975 落 main(279fb139d),本卡是那张表漏掉的第 6、7 个同形标本,各一行;PM 在认领评论 5316410458 里把相邻观察(record-alert.tsx 两处局部 props 类型)并入本卡一次收拾。

本正文里的诊断消息把尖括号写成 < tag >(带空格):GitHub 的正文净化器会把「< 紧跟字母」当 HTML 标签吃掉,原始消息里没有这个空格。

前提验证(先做,后写码)—— 卡面实测是 rc.6 时代的,已在现 pin 上重取

卡正文的 spec 实测标注的是 @objectstack/spec 17.0.0-rc.6,当前 pin 已是 GA 17.0.0(package.json / packages/components / packages/sdui-parser 三处都是 ^17.0.0)。臂要对齐契约而不是抄卡面,所以按 #4975 同款探针在现 pin 上重测了两个键的四向(外加 array,因为 'object' 臂刻意不收数组):

string i18n-map number boolean array
element:text.content(ElementTextPropsSchema) OK OK no(invalid_union) no(invalid_union) no(invalid_union)
element:button.label(ElementButtonPropsSchema) OK OK no(invalid_union) no(invalid_union) no(invalid_union)

两个键在 GA 上都是 z.ZodUnion< [ZodString, ZodRecord< ZodString, ZodString >] >,与卡面 rc.6 的答案一致 —— string=OK i18n-map=OK number=no boolean=no 仍然成立,前提未变(premise_still_valid: true)。

门侧同一次探针(manifestFromConfigs + validateTree,与 page.tsxkind:'jsx' 编译同一条路),改前:

declared element:text.content = "string"
declared element:button.label = "string"
element:text.content   (i18n map) -> warning/type-mismatch: < element:text >   prop "content" expected a string
element:button.label   (i18n map) -> warning/type-mismatch: < element:button > prop "label"   expected a string

两个键的告警逐字复现。行号漂移:卡面写 elements.tsx:109 / :319,:109 命中(content),label 实际在 :319(卡面准确);改后因注释各占几行落到 :117 / :328

record:alert 在 GA 上仍没有 ComponentPropsMap 条目(实测 'record:alert' in ComponentPropsMap === false),所以并入那两处的依据仍然是渲染器 + 已落地的发布面声明,不是 spec —— 与 #4975 的记述一致,没有因为换 pin 而改变。

改动(三处)

1. 两个标本各一行(packages/components/src/renderers/basic/elements.tsx)

{ name: 'content', type: ['string', 'object'], … }   // element:text
{ name: 'label',   type: ['string', 'object'], … }   // element:button

各带一段注释写明两条臂的依据(GA pin 上的 spec 联合 + 渲染器的 pickLocalized 读点),而不是只写「有两条臂」。机制不动。

2. 挂进标本验收面(apps/console/src/__tests__/component-input-union-specimens.test.ts)

新增一个 describe(#3832 那个原样不动,它是那次裁定的验收面,五标本的范围应当保持可读),里面三条测试:可达性、spec 裁决派生的臂集合、以及两个标本各一条正向 + 对照

对照按 #3832 的实证成对配齐:变异③(见下)实测到只撤机制时正向断言会空绿,红的只有对照。另外每个标本的臂集合不是重述 ['string','object'],而是从 spec 自己的裁决派生(COARSE_ARM_PROBES 逐值 safeParse,取通过的那些粗类型)—— 这是 text-input-inputs-spec-parity.test.ts 为第五标本采用的处置:#3832 关掉的是表达力那一半,「臂是否与契约相符」今天没有门禁(finding #4971),per-key 派生是替代品。派生本身也带一条守卫测试(全拒 → [] 会让两条比对空洞地相等)。

3. PM 并入(packages/plugin-detail/src/renderers/record-alert.tsx)

未导出的局部 RecordAlertProps 两处(properties.* + flat 兼容)的 title / bodystring 放宽。不新增导出,仍是局部。

string | I18nLabel(import type { I18nLabel } from '@objectstack/spec/ui')而不是手写 string | Record< string, string >,两个理由:

  1. 同一事实,仓内已有拼法。 packages/types/src/base.tsBaseSchema.label / .description 承载的就是这个事实,拼法逐字是 string | I18nLabel,import 自 @objectstack/spec/ui。新起一种拼法只会让同一件事在仓里有两种写法。
  2. 按引用绑定 spec,而不是复制它的形状。 I18nLabel = z.input< typeof I18nLabelSchema >,spec 若改动内联形态,这里跟着动;手写 Record< string, string > 是一份会漂的副本 —— 正是 scripts/check-spec-symbol-derivation.mjs 那条规则的形状(它按名字匹配,RecordAlertProps 不在其射程内,所以这里靠纪律而不是门禁)。注释里同时写明不是 KEYED 那套词表({ key, defaultValue },resolveKeyedI18nLabel),因为本文件的读点是 pickLocalized,收的是内联映射 —— Track the @objectstack family at 17.0.0-rc.6 — the adaptation surface beyond what objectstack#7100 could carry #4167 那对结构可混淆形状的老坑。

plugin-detail 已经依赖 @objectstack/spec(^17.0.0),import 不新增依赖。

序列化面复核(实测,不是引述折叠约束)

manifestFromConfigs(getPublicConfigs()) 在改前/改后各 dump 一份逐字比对(与 dev/manifest-dump.tsx 同一对函数):

public blocks 改前/改后:  57 / 57
逐字不变的条目:            55
变化的条目:                ["element:text", "element:button"]
JSON diff:                 2 个 hunk,各一处 "type": "string" -> ["string","object"]
数组形态的 input 合计:      7  (record:alert.title/.body, page:card.title,
                               page:header.title/.subtitle  +  本卡两个)

即单臂折叠约束在实测上成立:其余 55 个公开块一个字节没动,数组只出现在真正声明了联合的 7 个键上。

测试

pnpm exec vitest run apps/console/.../component-input-union-specimens.test.ts
    → Test Files 1 passed,   Tests 10 passed      (改前该文件 6 tests;本卡两标本此前缺席)
pnpm exec vitest run packages/sdui-parser/ packages/plugin-detail/ examples/schema-catalog/ \
                     packages/plugin-charts/src/index.test.ts packages/layout/
    → Test Files 116 passed, Tests 2630 passed
pnpm exec vitest run packages/components/
    → Test Files 147 passed, Tests 1320 passed
pnpm exec vitest run apps/console/
    → Test Files 51 passed,  Tests 574 passed
pnpm exec vitest run packages/app-shell/.../previews/ packages/app-shell/.../inspectors/
    → Test Files 91 passed,  Tests 1043 passed | 1 skipped
pnpm exec turbo run type-check --concurrency=2
    → Tasks 81 successful, 81 total
node scripts/check-control-bytes.mjs        → OK (4459 tracked text files)
node scripts/check-changeset-no-major.mjs   → OK
node scripts/check-changeset-presence.mjs   → OK (3 source files / 1 changeset)
node scripts/check-doc-component-types.mjs  → OK
node scripts/check-spec-symbol-derivation.mjs / check-package-self-import.mjs → OK
pnpm exec eslint <三个改动文件>              → 0 errors(33 个既有 no-explicit-any warning,非本卡新增行)

消费半径按「谁读 ComponentInput.type / ManifestInput.type」扫,不按包猜:manifestFromConfigs / validateTree / generateDts 的调用点共 24 个文件(packages/sdui-parserpackages/componentspackages/layoutpackages/plugin-chartsapps/consoleexamples/schema-catalogscripts/),全部覆盖在上面的批次里。另外扫了两个块在设计器面的 fixture(app-shellpreviews/block-config.ts:234 / :315 与其测试):那里是 kind: 'text'另一套词表,与注册的 inputs 无连接 —— 与 #4975 第 13 行的实测结论一致,无需跟改。

三条变异记录(先书面预判,后跑;变异前已 commit,还原用 git checkout --,⛔ stash)

① 撤回 element:text.content'object' 臂(留机制)。
预判 —— 与卡面派发模板预设的方向不同,如实先写下:派发卡预判的是「该标本对照面红」,但那是 #3832 变异①的方向(撤的是任一臂逻辑,数组 type 掉进旧 switchdefault: return null,什么都不产出 → 正向空绿、对照红)。本变异撤的是声明的一条臂、机制完好,单臂 'string' 照旧产出诊断,所以动的应该是正向那一半:臂集合比对红(['string'] vs spec 派生的 ['string','object']),i18n-map 正向断言红;对照仍然绿(42 / ['Account'] 照旧被报告),element:button 与派生守卫也绿。
实测:Tests 1 failed | 9 passed,唯一红的是 element:text.content 这条,失败点 AssertionError: expected [ 'string' ] to deeply equal [ 'object', 'string' ] —— 即臂集合比对(它是该 test 的第一条 expect,vitest 在此停下,所以 i18n-map 正向那条没跑到)。方向与我的预判一致,与卡面模板的预设相反,照直记录。

② 给 element:button.label 加一条 spec 不接受的假臂('number')。
预判:#3832 变异③把这件事分成两半 —— 「联合不是放行一切」那半成立,「臂是否对齐契约」那半有 per-block spec 断言的键会红、没有的会全绿(③b 在 page:card 上是 93 files / 856 tests 全绿)。本卡两标本的臂集合是从 spec 裁决派生的,所以这一半应当:['number','object','string'] vs ['object','string'];正向与对照都绿(true / ['Save'] 仍被三条臂一致拒绝)。
实测:Tests 1 failed | 9 passed,AssertionError: expected [ 'number', 'object', 'string' ] to deeply equal [ 'object', 'string' ]预判命中,并且这正是 #3832 ③b 留在绿里的那半 —— 本卡两个标本在本地把它闭上了(全局那半仍是 finding #4971)。

③ 把机制撤回 #3832 之前的形状(checkType 对数组 typedefault: return null),验证对照断言承重。
预判:全部七个标本的正向断言空绿、臂集合比对绿(它读的是 manifest 声明而不是门的行为),红的只有对照,报 expected [] to include 'type-mismatch' —— 空数组,即什么都没产出。
实测:Tests 6 failed | 4 passed,六条标本测试全红,失败点逐个落在对照行::151(page:header)、:169(page:card)、:189(record:alert)、:211(text_input)、:295(element:text.content):314(element:button.label),报的都是 AssertionError: expected [] to include 'type-mismatch'预判命中,本卡两标本的对照与 #3832 五标本的对照承重方式相同。

changeset

.changeset/element-text-button-i18n-arms-4970.md,@object-ui/components + @object-ui/plugin-detailminor,理由与 #3832 先例同档:这是发布面扩展而非破坏 —— 单字符串写法保持合法、其余 55 个公开块序列化字节不变、诊断行为只在两个键的合法写入上从「报」变成「不报」。按 AGENTS.md「objectui 不声明 major、fixed 组联动」的规则,扩展记 minor(⛔ major)。plugin-detail 那一处虽是未导出局部类型、没有发布面移动,但它是 packages/plugin-detail/src/** 的真实源码改动,按 check-changeset-presence.mjs 的前提一并列出并在正文里说明其性质(#4975 把只改注释的 packages/layout 排除在外,这一处比那个重一档)。

顺手发现的相邻缺陷(立卡,不并入本 PR)

草稿状态,等 PM 验收后再 undraft。


Generated by Claude Code

…label declare their real unions (#4970)

The sixth and seventh specimens of the objectui#3832 contradiction: both inputs'
own `description` teaches the author to write an inline translation map, both
renderers resolve one through `pickLocalized`, and both spec props schemas accept
one — while `type: 'string'` made the manifest gate report `type-mismatch` on
exactly that shape. Both blocks are in `PUBLIC_BLOCKS`, so it reached authors
through `sdui.manifest.json`, `sdui-intrinsics.d.ts` and the save gate.

Each is now `type: ['string', 'object']`, the union form #3832 landed. The arms
were re-measured on the `@objectstack/spec` 17.0.0 GA pin rather than copied from
the issue (written at 17.0.0-rc.6): `ComponentPropsMap['element:text'].content`
and `['element:button'].label` are both `string | Record< string, string >`, and
both refuse a number, a boolean and an array.

The acceptance test derives the expected arms from those verdicts instead of
restating them, and pairs each specimen with controls — reverting `checkType`'s
any-arm logic leaves the positive assertions vacuously green (an array-valued
`type` falls into the old switch's `default: return null`), so the controls are
the only half that moves.

`record:alert`'s renderer-local `RecordAlertProps.title` / `.body` are widened to
`string | I18nLabel` in the same pass: the same file resolves both through
`pickLocalized` and the block's published `inputs` have declared
`['string', 'object']` since #3832, leaving this unexported type as the last place
in the package claiming otherwise. Bound to the spec symbol rather than
re-spelling `Record<string, string>`, matching `BaseSchema.label` in
`packages/types/src/base.ts`.

Co-authored-by: Claude <noreply@anthropic.com>
…eaves narrow (#4970)

The widened doc comment read as if RecordAlertProps had no narrow slot left,
which is not true: action.label one level down is the same shape and was filed
as #4998 rather than fixed here, because its published surface declares
`action` as a bare object with the member shape in prose — there are no arms for
it to be aligned against yet. Say so at both places a reader would otherwise
take the stronger claim from.

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 25.3 KB 350 KB
Entry file index-m-WyWuOr.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
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) 40.21KB 10.79KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.71KB 1.22KB
auth (invitation-status.js) 1.22KB 0.70KB
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) 5.02KB 0.88KB
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) 498.86KB 111.27KB
core (index.js) 4.11KB 1.62KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 159.03KB 44.08KB
fields (index.js) 233.27KB 58.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 39.16KB 10.97KB
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) 9.35KB 3.31KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.42KB 1.42KB
permissions (evaluator.js) 5.12KB 1.74KB
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.81KB 0.83KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.75KB 18.37KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 127.85KB 32.73KB
plugin-designer (index.js) 212.39KB 42.83KB
plugin-detail (index.js) 240.05KB 60.05KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 120.42KB 29.03KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 197.61KB 53.03KB
plugin-kanban (index.js) 52.72KB 14.54KB
plugin-list (index.js) 111.22KB 26.98KB
plugin-map (index.js) 17.91KB 5.72KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.97KB 11.33KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 83.81KB 20.49KB
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.66KB 3.50KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.53KB 9.41KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.28KB 0.68KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (index.js) 4.77KB 2.16KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 6.92KB 2.40KB
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 (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 3.05KB 1.52KB
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

PM 验收 ✅ ACCEPT(#4970,批次 20)

实物核验(merge-base 34ae3274d 与报告一致):4 files,+215/−6 —— 两标本各一行改数组臂(臂在 GA pin 上重测而非抄卡面,record:alert 在 GA 上仍无 props schema、其依据是渲染器 + 已落地发布面的事实链保持完整);specimens 验收面 +131 行,两标本各配正向 + 双对照 + 从 spec safeParse 裁决派生的臂集合比对;PM 并入的 record-alert 局部类型经 @objectstack/spec/uiI18nLabel 符号绑定放宽(不复述、不新增导出)。模型标识 msg/diff 双 0;releases/ 零触碰;changeset 按 #3832 同档。

CI 亲读:20/20 check runs completed,零失败(两项 path-filter skipped 计绿)。序列化面实测:公开 manifest 逐字节 diff 恰好 2 个 hunk(55/57 条目不动),单臂折叠约束是测出来的不是引述的。

反向验证读数:变异①的方向修正是本单最有价值的读数 —— 派发词沿用了 #3832 变异①的「对照红」预设,dev 指出只删声明臂、机制完好时动的应是正向半边(诊断照常产出),先写下修正预判再实测命中(expected ['string'] to deeply equal ['object','string']);随后自加变异③(机制回退)补上「对照承重」的实证 —— 6 个标本全部红在对照行。变异②证明派生臂集合把 #3832 留给 #4971 的那半缺口在这两个键上就地关闭。方向修正如实报告不套模板,验收记为诚实产出。

finding #4998(action.label 第三同形槽,需 member-shape 机制,#3795 维)入池,不扩围判断正确。main 已前移无需手动 rebase —— merge queue 会按队列 ref 重算。undraft + auto-merge(squash)。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 17, 2026 14:19
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 17, 2026
Merged via the queue into main with commit 8b9dc62 Aug 17, 2026
20 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4970-elements-i18n-arms branch August 17, 2026 14:20
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.

element:text.content / element:button.label 是 #3832 那张表漏掉的第 6、7 个同形标本 —— 同一个矛盾,今天照样报 type-mismatch

2 participants