Skip to content

fix(i18n): retire the reader-less common.search key from the ten locale packs (#4392) - #4403

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4392-retire-common-search
Aug 12, 2026
Merged

fix(i18n): retire the reader-less common.search key from the ten locale packs (#4392)#4403
yinlianghui merged 1 commit into
mainfrom
claude/issue-4392-retire-common-search

Conversation

@yinlianghui

@yinlianghui yinlianghui commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Fixes #4392

Implements the RETIRE ruling on #4392. common.search lost its last consumer when #4375 / PR #4391 moved LookupField's dialog placeholder onto the reused table.search pack value; the key then sat in all ten locale packs with zero readers repo-wide.

Premise check (re-verified at claim time, against origin/main @ 5bf09fdba)

The premise holds: zero live readers. Every repo-wide occurrence, classified:

Where Class Disposition
packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts locale pack definition (10) deleted
packages/fields/src/widgets/useFieldTranslation.ts:10 dormant defaults-map copy (FIELD_DEFAULTS, module-local, no reader) deleted
packages/fields/src/complex-widgets.test.tsx:195 prose comment — history of #4375's concatenation kept, reworded (see below)
packages/plugin-chatbot/src/FloatingChatbotTrigger.tsx:22 dynamic common. + key reader not a reader of this key — its parameter is a two-member union type admitting only 'openChat' and 'closeChat', which cannot resolve to search. Untouched (in-flight surface, #4383).
LIVE READER none

Two mechanical notes for the next author:

  • The packs are nested objects, so a flat git grep "common.search" never matches them — it returns 2 hits repo-wide, neither of them a pack. The packs were enumerated with a common:-block-scoped scan instead.
  • fix(components): ActionParamDialog's select placeholder reads the common.select pack key #4397 (merged one commit earlier) uses common.select, a different key. It is untouched and is asserted by name in the new pin, precisely because it is one letter of intent away.

The ten-pack deletion

All ten together — the parity suite enforces all-or-nothing. Before / after:

ar:1 de:1 en:1 es:1 fr:1 ja:1 ko:1 pt:1 ru:1 zh:1     (10 pack/key pairs)
ar:0 de:0 en:0 es:0 fr:0 ja:0 ko:0 pt:0 ru:0 zh:0

Each pack lost exactly one line, between create: and filter:. Diffstat is 1 deletion per pack.

Retirement record — a negative pin, per measured precedent

git log -S on the key plus the repo's own prior pack-key removal (#4145, PR #4177, retiring report.editor.*) gives the convention: no tombstone comment in the packs; the trace is a dedicated negative pin test plus the changeset. This PR follows it with packages/i18n/src/__tests__/common-search-retired-4392.test.ts.

The pin is needed because every i18n gate in this repo runs call site to key, never key to call site:

  • check:i18n-keys asks whether each call site's key resolves in en — a key with no call site is never visited.
  • all-locales-key-parity compares the ten packs' key SETS to each other — one dead key present in all ten is exactly what it wants.
  • check:i18n-drift only fires when an en value CHANGES — this value was static.

So the key could return to all ten packs with every existing gate green. The pin asserts: absence in all ten packs (naming the pack), the neighbours survived as real translations (so a green cannot be bought by deleting the neighbourhood), no package or app reads or re-declares it, and no dynamic common. reader grows a search member. It is path-free about plugin-chatbot on purpose, so #4383's in-flight work cannot turn it red for an unrelated rename.

The one prose mention in complex-widgets.test.tsx was reworded from spelling a t() call around the key to naming the key bare — the same documentation convention #4145's pin wrote down, and what keeps the revival scan free of false positives without a comment stripper.

Changeset grading

minor for @object-ui/i18n, patch for @object-ui/fields — graded by the measured precedent, not by feel. #4145's changeset for the same class of change (.changeset/retire-report-editor-namespace-4145.md) is '@object-ui/i18n': minor, for this reason, which applies here identically: deleting a key from en narrows the exported TranslationKeys type (typeof en), so code indexing TranslationKeys at common.search stops type-checking. No runtime consumer existed to break, and no rendered string changes — the key never rendered. @object-ui/fields is patch: FIELD_DEFAULTS is a module-local, non-exported table read only when no LocalizationProvider is mounted, so dropping an entry nothing asks for narrows no public type. Never major, per the version-alignment rule.

Verification

Local, all green:

  • check:i18n-keysEvery in-scope call-site key resolves against the en pack (2858 keys), 3531 call sites scanned. This is the zero-reader proof executing: en no longer defines the key and no call site missed it.
  • check:i18n-drift0 en value(s) changed (0 key(s) added, 1 removed …). The removal verdict is the expected one, exit 0, not a red.
  • check:control-bytes — OK, 4101 tracked text files.
  • check-changeset-presence / check-changeset-no-major — OK.
  • Repo-root vitest packages/i18n/ + packages/fields/124 files, 2053 tests passed.
  • turbo run type-check for both packages — green, including i18n's two tsc commands (tsc --noEmit && tsc -p tsconfig.test.json).
  • turbo run lint for both packages — 0 errors (783 pre-existing warnings in fields, untouched files).

Reverse verification (direction predicted before running)

Each removal was taken out with a path-scoped git checkout origin/main and put back with git checkout HEAD — never git stash.

A. Restore ONE pack (de). Predicted: two independent gates red. Measured — both:

FAIL all-locales-key-parity  > de defines no key that en lacks
  de has 1 key(s) absent from en: expected [ 'common.search' ] to deeply equal []
FAIL common-search-retired-4392 > no pack defines `common.search`, in any of the ten packs
  expected [ 'de :: common.search' ] to deeply equal []

B. Restore ALL TEN packs. Predicted: parity goes green (ten identical key sets) and only the new pin stays red. This is the blind spot the pin exists for, and it measured exactly that:

Test Files  1 failed | 1 passed (2)
FAIL common-search-retired-4392 > no pack defines `common.search`, …
  expected [ 'en :: common.search', …(9) ] to deeply equal []

C. Restore ONLY the FIELD_DEFAULTS entry (packs left retired). Predicted: no pack gate can see this; the scan assertion catches it. Measured:

FAIL common-search-retired-4392 > no package or app reads `common.search`, and no fallback table re-declares it
  + "…/packages/fields/src/widgets/useFieldTranslation.ts :: declares common.search"

Branch restored to the committed state afterwards; working tree clean.

Surface discipline

Touched only packages/i18n/src/locales/*.ts, the new i18n pin, packages/fields/**, and the changeset. No dormant copy of the key existed in the constrained defaults tables of plugin-detail / plugin-list / plugin-designer (#4396) — nothing to report there. plugin-chatbot (#4383) was read for the premise check and not modified. No out-of-scope findings.


Generated by Claude Code

…cks (#4392)

`common.search` lost its last consumer when objectui#4375 / PR #4391 moved
LookupField's dialog placeholder onto the reused `table.search` pack value.
The key then existed in all ten locale packs with zero readers repo-wide.

Deletes it from all ten packs together (the parity suite enforces the
all-or-nothing shape), drops the dormant copy from @object-ui/fields'
no-provider fallback table, and adds a negative pin: every i18n gate in this
repo runs call site to key, so none of them can see a key with no call site.

Fixes #4392
@vercel

vercel Bot commented Aug 12, 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 12, 2026 2:51am

Request Review

@github-actions github-actions Bot added the tests label Aug 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-Y9-oUoUb.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) 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) 489.20KB 108.43KB
core (index.js) 2.99KB 1.14KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 153.42KB 41.19KB
fields (index.js) 228.33KB 56.61KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
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.33KB 1.20KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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) 45.23KB 12.45KB
plugin-charts (index.js) 62.18KB 17.67KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 121.56KB 31.63KB
plugin-designer (index.js) 210.91KB 42.67KB
plugin-detail (index.js) 239.00KB 59.76KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.58KB 27.68KB
plugin-gantt (index.js) 164.14KB 39.98KB
plugin-grid (index.js) 187.99KB 49.92KB
plugin-kanban (index.js) 48.60KB 13.41KB
plugin-list (index.js) 110.12KB 26.74KB
plugin-map (index.js) 18.05KB 5.80KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 42.27KB 11.36KB
plugin-timeline (index.js) 26.21KB 7.52KB
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) 23.71KB 7.96KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.23KB 0.66KB
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 (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

ACCEPT — PM 复核 (session session_017Qqyix2QcnpUC9XeYVDzx3), closes #4392.

Flipping ready + arming auto-merge.


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 12, 2026 03:02
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit ac853ce Aug 12, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4392-retire-common-search branch August 12, 2026 03:02
This was referenced Aug 12, 2026
yinlianghui pushed a commit that referenced this pull request Aug 13, 2026
`generateTimeScaleHeaders` is reachable from the package entry (`index.tsx`
does `export * from './renderer'`) and its published declaration grew an
optional trailing `locale?: string`. Entry-reachable additive API growth is
minor, not patch — patch is for changes with no API-surface movement at all.

`dist/index.d.ts` being byte-identical does not argue for patch: the entry
re-exports by reference, so the resolved public surface moved even though the
entry file's bytes did not. The contrapositive of #4496, which was graded patch
precisely because its .d.ts additions were NOT re-exported from the entry;
#4403 / #4177 / #4485 / #4495-regrade are the line this follows.

Additive and back-compatible is what minor means — no consumer breaks, existing
three-argument callers keep compiling and keep producing byte-identical output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] common.search has zero readers repo-wide after PR #4391 — retire from the ten packs, or keep as vocabulary?

2 participants