Skip to content

chore(i18n): delete the dead workflow.* and publicForm.demo.* namespaces from the ten packs (#4742) - #4743

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4742-dead-namespace-deletion
Aug 15, 2026
Merged

chore(i18n): delete the dead workflow.* and publicForm.demo.* namespaces from the ten packs (#4742)#4743
yinlianghui merged 1 commit into
mainfrom
claude/issue-4742-dead-namespace-deletion

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Part of #4730

Fixes#4742

Deletes two dead i18n namespaces from all ten locale packs: workflow.* (58 keys) and publicForm.demo.* (36 keys). 94 keys x 10 packs = 940 translated strings with no reader anywhere in the repo. No behaviour change is possible: a key with no reader cannot be read.

Verified at c0a3ba7b8 (git rev-parse --short HEAD at the run that produced every number below).

Re-measured first — the umbrella's counts predate today's merges

node scripts/check-i18n-dead-keys.mjs --json, run on this tree before any edit (origin/main at af460fb6d):

umbrella #4730this tree, beforethis tree, after
total pack keys292729332839
referenced keys1377613811
candidates626626532
CONFIRMED384384294
NEEDS-REVIEW242242238
workflow.*54 CONFIRMED / 4 NR54 CONFIRMED / 4 NR0 / 0
publicForm.demo.*36 CONFIRMED / 0 NR36 CONFIRMED / 0 NR0 / 0

The deltas are exact and account for the whole change: −94 pack keys (58 + 36), −90 CONFIRMED, −4 NEEDS-REVIEW (the four fixture-mentioned workflow.* keys). Both namespaces are gone from the report; nothing else moved.

Evidence per namespace — the #4658 / PR #4731 standard, re-verified independently

Zero call sites (AST pass). Every key in both namespaces was a candidate, which by construction means no literal t()/tt() argument, no plural-suffixed spelling, no returnObjects branch, and no dynamic template head reaches it. Cross-checked by hand:

grep -rnE "(t|tt)\(\s*[\`'\"](workflow|publicForm)" packages apps examples e2e --include="*.ts" --include="*.tsx"| grep -v /locales/
grep -rnE "\.(workflow|publicForm)\b|\.demo\b" packages/i18n/src packages/*/src apps/*/src --include="*.ts" --include="*.tsx"| grep -v /locales/

Both return nothing — no call site, and no object-path access to the namespaces either.

Zero textual footprint outside the packs (safety net). All 58 workflow.* keys greped as fixed strings across the whole repo return exactly four hits, all in i18n test fixtures (see below), and nothing else:

grep -rFf workflow-keys.txt . --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.turbo | grep -v "^./packages/i18n/src/locales/"
grep -rF "publicForm.demo". --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=coverage --exclude-dir=.turbo

publicForm.demo returns zero hits repo-wide — the packs nest it as an object literal, so even its defining lines never spell the dotted form.

Plausible-consumer spot check.packages/plugin-designer/src/ProcessDesigner.tsx imports no translation hook at all:

grep -cE "useTranslation|useObjectTranslation|useDesignerTranslation|@object-ui/i18n|react-i18next" packages/plugin-designer/src/ProcessDesigner.tsx # 0, exit 1

It hardcodes the same vocabulary in English instead — { label: 'User Task', value: 'user-task' }, { label: 'Service Task', … }, { label: 'Exclusive Gateway', … }. This is not a package-wide absence of i18n: six sibling components in the same package (AppCreationWizard, DashboardEditor, ObjectManager, BrandingEditor, NavigationDesigner, FieldDesigner) do use a translation hook. ProcessDesigner.tsx alone was never wired up.

Two checks beyond the card's standard, both clean:

  • Sibling repo.../objectstack has zero references to either namespace (its one workflow. hit is the filename workflow.zod.ts in a spec test — not an i18n key).
  • The i18n baselines. Neither scripts/i18n-en-drift-baseline.json nor scripts/i18n-call-site-key-baseline.json names any key in either namespace, so no waiver ledger is left pointing at a deleted key.

No key in either namespace turned out to have a live reader, so nothing was excluded from the deletion.

The four workflow.* fixture mentions: rows deleted, not re-pointed

Both fixtures pin those specific keys rather than merely needing a key, so substituting a live key would make each file state something untrue. The card's other branch (update to live keys) does not apply to either.

ellipsis-glyph-3878.test.ts carries CONVERGED_KEYS, a census of "every key that held an ASCII ellipsis in at least one of the ten packs on the commit before the fix". workflow.fromPlaceholder and workflow.toPlaceholder were two of the 35. Naming a different key there would claim that pass converged a key it never touched. Their rows are deleted, the length assertion moves 35 → 33, and the census note records why the number dropped — the historical "312 pack values changed" count is untouched, because retiring a key later does not change what that pass did.

untranslated-identity-4376.test.ts carries LEGITIMATE_IDENTITIES, a key-level allowlist where each entry is a fact about one key's value ('workflow.webhook': 'Webhook — the protocol term these packs use untranslated.'). An entry cannot outlive its key or be transferred to another one. Both entries are deleted, with a comment recording that the file's own no dead entries guard is what would have caught a leftover.

Reverse verification (fix committed first, then the two fixture files alone reverted to origin/main while the pack deletions stayed):

× keeps the allowlist honest — no dead entries
× keeps an ellipsis in every pack for each of the 35 keys this pass converged
AssertionError: en workflow.fromPlaceholder missing: expected 'undefined' to be 'string'
AssertionError: these allowlist entries no longer match any identity — delete them, or the
allowlist is covering keys it no longer describes: expected [ 'workflow.webhook', …(1) ] to deeply equal []
Test Files 2 failed (2) | Tests 2 failed | 5 passed (7)

Expected direction, observed: red, both guards firing by name. Restored with git checkout claude/issue-4742-dead-namespace-deletion -- and the two fixture paths; git diff --stat HEAD is empty, so the tree is byte-identical to the commit, and the suite was re-run green from that restored state.

One bounded in-place fix, named

untranslated-identity-4376.test.ts's header said "22 keys below" while the list held 23 on origin/main — nothing asserts that number, so an addition drifted it without anyone noticing. My deletion moves the same sentence again (to 21). Rather than restate a number that will drift a third time, the count is removed from the prose: the list is its own count, and the file's no dead entries assertion is what keeps it honest. Same file, same defect class (allowlist bookkeeping invalidated by this deletion), mechanical, no new verification surface.

Out of scope, deliberately untouched

console.objectView.* (decision pending on #4730), the not-yet-spot-verified smaller namespaces, and red-ifying the dead-keys script (--strict stays unwired). One observation for #4730 rather than this PR: the parentpublicForm.* namespace is itself largely unread — 12 CONFIRMED and 7 NEEDS-REVIEW of its 19 remaining keys, with no t() call site anywhere in packages/ or apps/. It is left exactly as it was; it belongs to the umbrella's namespace-by-namespace pass, not to this carve-out.

Gates run — commands, so a re-test is a re-run

All at c0a3ba7b8, from the repo root of a worktree cut from af460fb6d:

node scripts/check-i18n-dead-keys.mjs --json # both namespaces absent; 2839 pack keys
node scripts/check-i18n-call-site-keys.mjs # exit 0 — 2415/2415 literal keys resolve against the en pack (2839 keys)
node scripts/check-i18n-en-drift.mjs # exit 0 — "0 en value(s) changed (0 added, 94 removed — those are all-locales-key-parity's)"
node scripts/check-changeset-presence.mjs # exit 0 — 12 source files, 1 changeset
node scripts/check-changeset-fixed.mjs # exit 0
node scripts/check-changeset-no-major.mjs # exit 0
node scripts/check-control-bytes.mjs # exit 0 — 4260 tracked text files
pnpm exec vitest run packages/i18n/ # 45 files, 804 tests passed (includes all-locales-key-parity)
pnpm --filter "@object-ui/i18n^..." build # build the dep closure first in a fresh worktree
pnpm --filter @object-ui/i18n type-check # exit 0
pnpm --filter @object-ui/i18n lint # 0 errors (35 pre-existing warnings, none in a file this PR touches)
pnpm exec vitest run scripts/__tests__/check-i18n-dead-keys.test.ts \
scripts/__tests__/check-i18n-en-drift.test.ts scripts/__tests__/check-i18n-call-site-keys.test.ts \
packages/app-shell/src/views/RecordFormPage.i18n.test.tsx \
packages/plugin-grid/src/ImportWizard.i18n-parity.test.ts \
packages/app-shell/src/console/organizations/__tests__/ \
apps/console/src/pages/auth/__tests__/AcceptInvitationRoute.test.tsx # 17 files, 236 tests passed

The last one is the sweep of every consumer of the pack objects outside packages/i18n — the files that import builtInLocales and would see the deletion. check-i18n-en-drift abstaining rather than firing is the designed division of labour: deletions are all-locales-key-parity's business, and it is green.

en drops 109 lines, the nine translation packs 106 each.


Generated by Claude Code

…espaces (#4742)
94 keys x 10 packs = 940 translated strings with no reader anywhere in the
repo. `node scripts/check-i18n-dead-keys.mjs` scored `workflow.*` 54/58
CONFIRMED (the other 4 appear only as mentions in two i18n test fixtures) and
`publicForm.demo.*` 36/36 CONFIRMED with zero textual footprint outside the
packs. The plausible consumer of the workflow vocabulary,
`packages/plugin-designer/src/ProcessDesigner.tsx`, hardcodes English and
imports no translation hook at all, while six sibling components in the same
package do use one.
The two fixture files that named four `workflow.*` keys are pinning those
specific keys, not merely using a key, so their rows are deleted rather than
re-pointed: `ellipsis-glyph-3878.test.ts` carries a census of the keys that
pass converged, and `untranslated-identity-4376.test.ts` carries a key-level
allowlist whose entries are facts about one key's value.
Part of #4730.
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 15, 2026 10:27pm

Request Review

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM review — ACCEPT (reviewer of record, session session_01RnQd8iMMUwXQEV1crFmQiQ)

Deletion-class, so all reference faces were independently re-run on origin/main — the PR body's commands made the re-test a re-run, as asked:

  1. Zero call sites: my t()/tt() grep across packages/apps/examples/e2e (locales excluded) returns nothing for either namespace; the object-path variant (.workflow / .publicForm) counts zero after locale exclusion (counted untruncated — today's standing lesson applied).
  2. Textual footprint: distinctive-key sampling repo-wide (workflow.fromPlaceholder, workflow.webhook, workflow.boundaryEvent, publicForm.demo) hits exactly the two known fixture files and nothing else — matching the four-mention account; publicForm.demo has zero hits anywhere including the packs (nested object literal, never spelled dotted).
  3. Plausible consumer: ProcessDesigner.tsx on origin/main has zero translation imports (count 0), and the dev's strengthening observation stands — six siblings in the same package do use hooks, so this is one unwired component, not a package-wide absence.
  4. Diff exactness: 13 files — ten packs (−106 lines each, en −109), the two fixture files, one changeset; −1075/+63 total. The before/after sweep deltas are fully accounted for (−94 keys, −90 CONFIRMED, −4 NEEDS-REVIEW).
  5. Fixture handling is the correct branch of the dispatch's fork: both fixtures pin those specific keys (a converged-key census; a key-level allowlist), so substitution would have made each file state something untrue — rows deleted, and the reverse verification turned exactly the two guards red by name before restore. The bounded in-place fix (removing the drift-prone "22 keys below" prose count) is same-file, same-defect-class, and replaces a number with the list's own self-count — accepted.
  6. Umbrella protection held: body line 1 Part of #4730 carries no closing keyword; Fixes #4742 is the sole closing keyword. Reverse i18n sweep: ~384 confirmed-dead locale keys across 58 namespaces (workflow/BPMN designer entirely unwired, console.objectView oversized, more) #4730 stays open, and the dev's publicForm.*-parent observation is correctly parked there rather than filed as a duplicate.

Changeset: @object-ui/i18n patch present; no skip-changeset applied. Gates at c0a3ba7b8: local union green including the pack-consumer sweep outside packages/i18n; awaiting CI — will flip ready + auto-merge once Lint + Type Check + Test shards 1-4 conclude success at this head.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)24.7 KB350 KB
Entry fileindex-DOl78Vau.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)25.13KB5.40KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)38.46KB10.17KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)490.42KB108.84KB
core (index.js)3.79KB1.52KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)157.05KB43.28KB
fields (index.js)231.18KB57.42KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.84KB1.45KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.98KB10.85KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.35KB3.31KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.89KB1.22KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.81KB0.83KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.86KB12.91KB
plugin-charts (index.js)64.44KB18.28KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)121.90KB31.76KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)239.81KB59.97KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)114.72KB27.70KB
plugin-gantt (index.js)164.30KB40.02KB
plugin-grid (index.js)192.10KB51.24KB
plugin-kanban (index.js)52.72KB14.54KB
plugin-list (index.js)111.14KB26.92KB
plugin-map (index.js)18.16KB5.81KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)41.38KB11.09KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)83.81KB20.49KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)27.64KB9.44KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.28KB0.68KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@yinlianghui
yinlianghui marked this pull request as ready for review August 15, 2026 22:40
@yinlianghui
yinlianghui added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit 564b605Aug 15, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4742-dead-namespace-deletion branch August 15, 2026 22:40
Sign up for freeto 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.

Delete the two spot-verified dead i18n namespaces: workflow.* (54 keys) and publicForm.demo.* (36 keys) across the ten packs

2 participants

@yinlianghui@claude