Skip to content

feat(i18n)!: retire 23 measured-dead pack keys, two families whole (objectui#8754) - #9487

Merged
os-try-charles merged 2 commits into
mainfrom
claude/issue-8754-retire-dead-pack-keys-round2
Sep 14, 2026
Merged

os-try-charles merged 2 commits into
mainfrom
claude/issue-8754-retire-dead-pack-keys-round2

Conversation

@claude

@claude claude Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #8754

Round 2 of the director seat's summon #22 ruling (2026-09-12): instrument first, deletion second. Round 1 — the instrument repair — landed c4a1d39fe9 (PR #9222). This is the deletion.

The admission criterion was a measurement, not this card's body

The 25 keys in the card's body were not the input. pnpm check:i18n-dead-keys was re-run on this branch's own base, ff1d5ea8d1, and the deletion is what it confirms today.

Its verdict, quoted from its own output:

Pack keys (en, assumed parity-identical across all ten): 3010. Referenced by a t()/tt() call site (literal + plural-suffixed + returnObjects branch + dynamic-template-reachable): 15806.

358 candidate(s) with no call site this pass can see, across 46 namespace(s): 119 CONFIRMED (no textual footprint anywhere else in the repo either), 239 NEEDS-REVIEW …

The population named in words: 3010 keys defined by the en pack (the ten packs are parity-identical, which all-locales-key-parity.test.ts separately enforces); of those, 358 have no call site the AST pass can see; of those, 119 also have no bounded textual occurrence anywhere else in the repository — that is the CONFIRMED tier. This run agrees with round 1's recorded 119 CONFIRMED, and NEEDS-REVIEW has moved 238 → 239 since (one key joined, from ordinary tree movement).

Does it agree with the card's 25? No — the measured population is 23, and the difference is the card's arithmetic

Every one of the 13 keys PR #8753 uncovered is still CONFIRMED today — none moved tier. Both families are intact, each 5 CONFIRMED + 1 NEEDS-REVIEW, exactly as the ruling anticipated.

The card reached 25 as 13 + 6 + 6, double-counting the two leaves that belong to both sets: approvals.reject and marketplace.pricing.free are each one of the 13 and a member of one of the families. The true union is 23. ⇒ no key was dropped for being live, and no key was added; the card simply counted two keys twice.

Family completeness, each zero carrying a control that fires

The ruling's family rule: a family is whole when every member is CONFIRMED, or is NEEDS-REVIEW whose only hits are non-liveness. Both families qualify, and both are removed as roots, not emptied leaf by leaf.

Membership was read from the pack source in all ten packs, not inferred: approvals holds exactly 6 members and marketplace.pricing exactly 6, in every pack. All 12 are candidates ⇒ no member has a call site.

approvals.* — probe and control in the same command, over packages/ apps/ examples/ e2e/ content/ scripts/ minus the ten locale packs (which define every key by construction):

probe result
approvals.(approve|approveSuccess|comment|reject|rejectSuccess|rejectConfirm) at key boundary 1 hit, and it is packages/app-shell/CHANGELOG.md:6161 — changelog prose about a past change. Zero source hits.
control: approvalsInbox. , same command shape HITSDeclaredActionsBar.tsx:230/236/241, approverIdentity.ts:365/373, …

approvalsInbox hitting while approvals. does not is the reading the card predicted.

marketplace.pricing.*:

probe result
marketplace.pricing. at key boundary 1 hit, packages/i18n/src/__tests__/untranslated-identity-4376.test.ts:105 — a pin-test allowlist entry
any t()/tt() call whose key mentions pricing at all 0
the word pricing anywhere in packages/app-shell/src/console/marketplace/ 0
control: marketplace.category. , same command shape HITSMarketplacePackagePage.tsx:654, MarketplacePage.tsx:185
control: any t() call whose key mentions category HITS — 3 call sites

marketplace.category. is a collected dynamic template head, which is exactly why none of that family was ever a candidate — and why marketplace.pricing., which has no head, was.

The two NEEDS-REVIEW members are the two the ruling named as admissible, and both hits are non-liveness: a changelog line and a pin test. ⇒ both families retire whole.

The eleven individual leaves

Each was held out of an earlier sweep by a longer live sibling that merely contains it, until PR #8753 put a key-boundary requirement on both sides of the text probe. A repo-wide bounded grep over all 23 keys returns exactly the two hits above and nothing else — and that same command returning non-zero for those two is what proves the other 21 zeros are readings rather than a broken pattern.

Firing control on the deletion itself

⭐ Without this, "the keys are gone" is indistinguishable from "the pack reader broke".

dead-pack-keys-retired-8754.test.ts asserts, in the same run: every retired key is absent from all ten packs; both family roots are gone; and 20 named surviving siblings still resolve to a non-empty string in all ten packs — including the longer sibling that actually renders in each of the eleven leaf cases (sidebar.helpTooltip for sidebar.help, home.starredApps.title for home.starred, …). A sample across writing systems pins that those survivors are real translations, not the English value ten times.

Reverse-verified. One retired key was restored into one pack (zh) on the committed tree, proven to have landed on disk by blob hash (3aab235a78de6dff3fa1) and by the leaf spelling going 0 → 1:

FAIL  all-locales-key-parity.test.ts > zh defines no key that en lacks
  AssertionError: zh has 1 key(s) absent from en: expected [ 'sidebar.help' ] to deeply equal []
FAIL  dead-pack-keys-retired-8754.test.ts > no pack defines any retired key, in any of the ten packs
  AssertionError: … expected [ 'zh :: sidebar.help' ] to deeply equal []
Test Files  2 failed (2)
     Tests  2 failed | 35 passed (37)

Both pins red and name the pack and the key, while 35 tests in the same run stay green — that green half is the survivor assertion, so the red is about the retired key and not about the reader. The mutation was restored under a shell trap and the restore verified by state, not exit code: on-disk hash equals the HEAD blob, git diff HEAD empty, git status clean.

All-locales key parity — before and after

Measured on two real trees, not inferred.

tree test files tests
before ff1d5ea8d1 (this branch's base, in its own worktree) 66 passed 1120 passed
after ebcbb22e5f 67 passed 1125 passed

Parity passes on both sides; the +1 file / +5 tests is exactly this PR's new pin. Parity is preserved rather than trivially satisfied because every deletion is a ten-pack edit — 27 source lines removed from each of the ten packs, identical in each.

⚠️ The self-pollution trap, walked into and measured

The card forbids pinning keys by spelling them, because a spelled key becomes a textual hit for the sweep and is pushed back into NEEDS-REVIEW. A first draft of the new pin's header comment spelled out five keys as a warning not to name them. The post-deletion census then read 93 CONFIRMED where the arithmetic said 98 — those five, demoted by the very sentence telling the reader not to do it. The spellings were replaced with a description of the shape, and the census landed on 98 exactly.

Recorded here and in the test's header because the demotion is silent, and the five keys are not exotic: they are the nearest live-looking sibling in each of the dashboard, form, sidebar, home and workspace namespaces, and every one of them is CONFIRMED-dead itself today.

Census, before → after, with every number accounted for

before (ff1d5ea8d1) after (ebcbb22e5f) delta
pack keys (en) 3010 2987 −23
candidates 358 335 −23
CONFIRMED 119 98 −21
NEEDS-REVIEW 239 237 −2

The set that left the candidate list is exactly the 23 deleted keys; no key joined, and no surviving key changed tier. 21 of the 23 were CONFIRMED and 2 were the admissible NEEDS-REVIEW members ⇒ 119 − 21 = 98 and 239 − 2 = 237, which is what the run prints.

Bytes — re-measured, ⛔ no budget constant moved

The ruling asks for the i18n-locales chunk figure. ⚠️ That chunk no longer exists: objectui#7479 made nine of the ten catalogues lazy and re-keyed the ceiling to i18n-locale-en. Reported against the successor, from two real console builds:

before after delta
eager i18n-locale-en chunk 39.6 KB gz 39.4 KB gz −152 bytes
ten catalogues, gzipped 456,642 B 454,801 B −1,841 B (−0.40%)
ten catalogues, uncompressed 1,495,158 B 1,488,126 B −7,032 B (−0.47%)
aggregate console eager closure 3061.4 KB 3061.3 KB −0.1 KB

check:eager-closure green on both trees. ⛔ PER_CHUNK_GZIP_CEILINGS, PER_CHUNK_BASELINE and MAX_EAGER_CLOSURE_GZIP_BYTES are untouched — this PR changes no file under scripts/.

Gates run

gate exit reading
pnpm --filter @object-ui/i18n test 0 67 files / 1125 tests
pnpm --filter @object-ui/i18n type-check 0 tsc --noEmit + test tsconfig
pnpm --filter @object-ui/i18n lint 0 0 errors, 33 pre-existing warnings
check:i18n-keys 0 "Every in-scope call-site key resolves against the en pack (2987 keys)" — the direct proof no call site asks for a deleted key
check:i18n-drift 0 0 en values changed in range
check:i18n-designer-parity 0 every en row has a zh row
check:i18n-dead-keys 0 the census above
check:eager-closure 0 table above
check:eager-locale-catalogues 0 ⚠️ first returned exit 2 PREREQUISITE NOT MET (needs a built bundle) — re-run after building, ⛔ not recorded as a pass
check:control-bytes 0 7658 tracked text files
check:test-path-roots 0 new pin's roots classified
check:new-line-citations 0 0 new citations
check-changeset-presence 0 measured the obligation: 12 published source files of 1 released package ⇒ 1 changeset
check-changeset-no-major 0 no major declared

gates_weakened: NONE — no threshold lowered, no ceiling raised, no non-vacuity floor moved (the > 2000 floors read 2987), no test skipped.

Repo-wide eslint . is CI's run, not this PR's: the 13 changed TS files lint 0 errors / 0 warnings, and pnpm lint is turbo run lint (per-package), whose @object-ui/i18n leg is the row above.

Changeset — measured, not assumed

Owed, and check-changeset-presence said so in its own words. @object-ui/i18n is published (private unset, v17.6.0) and in the 40-package fixed release group, and this PR changes 12 files under its src/. .changeset/8754-dead-pack-keys-retired.md lists every one of the 23 keys, states the breaking semantics and the out-of-repo consumer risk the ruling accepts, and names the live replacement surface for each family. Marked minor per this repo's rule that a changeset never declares major.

维护者速读(草稿)

改了什么:从十个语言包里删掉 23 条已确认没人用的句子 —— 两个完整的功能族(审批 approvals.*、应用市场定价 marketplace.pricing.*),外加 11 条零散的旧句子。

为什么改:这些句子仓库里没有任何地方再引用,但仍随每个版本发布、占着打包预算。卡片正文写的是 25 条,但那是算错了(有两条被数了两遍);本次按仪器当天实测的结果删了 23 条,不是照抄卡片上的数字。

风险与代价(含回滚):@object-ui/i18n 是对外发布的包。仓库外如果有人在用被删的句子,那里会显示原始键名而不是句子,不报错。这个风险是维护者 2026-08-27 已经拍板接受的(「项目在创业阶段,用户也很少,短期不考虑渐进」)。回滚 = 一次 revert,把键加回去即可。打包体积减少约 1.8 KB(gzip,十个语言包合计)。

席位意见:(留空,待评审)

你要做的:确认「立即退役、不设过渡期」这一条仍然成立;如果您希望改成保留一段时间,请说一声,这个 PR 需要重做。


🤖 Generated with Claude Code

https://claude.ai/code/session_013VGeMu3p6qEFWR6K6GGLaW


Generated by Claude Code

…bjectui#8754)

Re-ran `check:i18n-dead-keys` on this change's own base after the objectui#9222
instrument repair and deleted what it confirms today, rather than the list frozen
in the card's body.

The card said 25; the measured population is 23. The difference is arithmetic in
the card, not tier movement: it counted eleven non-family leaves plus two families
of six, double-counting the two leaves that belong to both sets. Every one of the
13 keys PR objectui#8753 uncovered is still CONFIRMED today.

Both families retire whole, as roots rather than emptied leaf by leaf. Their two
NEEDS-REVIEW members are admissible under the ruling's family rule — one hit each,
both non-liveness (a changelog line; a pin-test allowlist entry, deleted with the
key on that file's own `workflow.*` precedent).

Census, same instrument, before -> after:
  pack keys     3010 -> 2987   (-23)
  candidates     358 ->  335   (-23, exactly the deleted set)
  CONFIRMED      119 ->   98   (-21)
  NEEDS-REVIEW   239 ->  237   (-2)
No key joined the candidate set and no surviving key changed tier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VGeMu3p6qEFWR6K6GGLaW
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3061.5 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-CGHT5tbU.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 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.68KB 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) 544.93KB 130.50KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 213.54KB 59.33KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
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.75KB
mobile (index.js) 1.99KB 0.87KB
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.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.92KB 14.22KB
plugin-charts (index.js) 71.33KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 252.46KB 65.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.83KB 57.97KB
plugin-kanban (index.js) 46.63KB 14.53KB
plugin-list (index.js) 112.67KB 27.68KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 84.36KB 20.78KB
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.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 99.04KB 32.62KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
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 (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3061.6 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-Cvt4yK79.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 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.68KB 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) 544.93KB 130.50KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 213.54KB 59.33KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
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.75KB
mobile (index.js) 1.99KB 0.87KB
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.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.92KB 14.22KB
plugin-charts (index.js) 71.33KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 252.46KB 65.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.83KB 57.97KB
plugin-kanban (index.js) 46.63KB 14.53KB
plugin-list (index.js) 112.67KB 27.68KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 84.36KB 20.78KB
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.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 99.04KB 32.62KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
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 (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

CI green on the current head — and the landing probe, written BEFORE the merge

domain:devx @ objectui seat, session_013VGeMu3p6qEFWR6K6GGLaW, R58, 2026-09-14T10:5xZ. Head 19f9da8e44f593f53d1e3bdfb6e8c08dc9f66111.

The CI reading, with a control that fires

reading value
check runs on this head, enumerated 36 of total_count 36
success 32
skipped 3 (Test (coverage), Test (coverage shard …), dependabot)
failure 0
still running 0 — Test (shard 1/4) settled at 10:57:18Z

32 + 3 + 0 + 1 = 36 ✓ (the last before shard 1 landed).

CONTROL, same instrument, same call shape, same minute — the identical check-runs read against objectui#9488 returns 34 of 34 with Bundle Analysisconclusion: "failure". ⇒ this reader demonstrably shows red, so the 0 above is a reading and ⛔ not a broken instrument.

⚠️ First enumeration returned only 30 of 36 and I did not report on it — the gap was closed with an explicit full page before any conclusion was drawn.

File surface, verified independently of the PR body

14 files: 10 locale packs at exactly +0 / −27 each, uniform. That is the PR body's "27 source lines removed from each of the ten packs, identical in each" confirmed from the file list rather than taken on trust.

⚠️ mergeable_state: behind — measured, and deliberately not chased

main...19f9da8e = diverged, ahead 2 / behind 1 (CONTROL: main...main = identical, so the comparison endpoint is answering). The head already carries a base merge (19f9da8e, 10:37:57Z). main has advanced 6 times in the last hour, so re-merging to chase it restarts ~20 minutes of CI against a target that moves again meanwhile. ⇒ the merge queue builds and tests the merge commit; that is what it is for. ⛔ No treadmill.


⭐ Landing probe — fixed now, before the merge, so it cannot be fitted to the result

⚠️ A first draft of this probe was BLIND, and pre-validation is what caught it. I intended to assert the retired leaves read 0 on merged main. Measured on the PR head: ^\s*help: reads 4 (not 0) and ^\s*approvals: reads 1 (not 0) — because those leaf names exist in several namespaces, and this PR retires one of each. An "expect 0" probe would have gone red on a correct merge. ⇒ the probe is delta-shaped, not absolute.

# probe expectation control in the same reading
P1 diff M^ → M over the ten packages/i18n/src/locales/*.ts each +0 / −27 dead-pack-keys-retired-8754.test.ts shows +253 / −0 ⇒ the reader can see additions, so +0 is a reading
P2 GET contents packages/i18n/src/__tests__/dead-pack-keys-retired-8754.test.ts at merged main 200 a sibling path known absent ⇒ 404
P3 counts in packages/i18n/src/locales/en.ts, measured at the actual M^ and M ^\s*help: −1, ^\s*approvals: −1, ^\s*pricing: −1 survivors unchanged across the same pair: helpTooltip, approvalsInbox, ^\s*category:
P4 resolve M and M^ after the merge, from the merge commit itself

P3's absolute numbers are NOT pinned here on purpose. On this branch's own base they read 5 / 2 / 1, but M^ is whatever main is when the queue builds it, and other PRs touch these packs. The delta is the assertion; the endpoints get measured, never predicted.

P4 is a red line for this seat: the parent gets resolved from the actual merge commit after the fact. Predicting M^ has bitten this lane four times, and the parent has repeatedly turned out to be this seat's own previous merge.

⇒ Flipping ready, re-reading Governed Surface Queue Guard after the flip, then enqueueing. ⛔ No approval from this seat, ⛔ no direct merge, ⛔ no queue bypass.


Generated by Claude Code

@os-try-charles
os-try-charles marked this pull request as ready for review September 14, 2026 10:59
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 14, 2026

Copy link
Copy Markdown
Collaborator

⛔ Dequeued at 11:22:13Z — ⭐ the tests PASSED. Root-caused, ⛔ not called a flake, and re-queued once.

domain:devx @ objectui seat, session_013VGeMu3p6qEFWR6K6GGLaW, R58, 2026-09-14T11:3xZ. ⚠️ This PR did not mergeen.ts on main reads 189,349 bytes, byte-for-byte the pre-deletion size (this head is 188,592), and ^\s*pricing: still reads 1. ⛔ Nothing landed.

What actually happened

Merge group gh-readonly-queue/main/pr-9487-56223c96ab…, CI run 34836062981:

step conclusion duration
setup → install (7 steps) success 33s
Run tests (shard 1/4) success 1165s = 19m25s
Run built-artifact pins (dist project) cancelled 14s

Job wall clock 20m14s against .github/workflows/ci.yml:752 timeout-minutes: 20. 33 + 1165 = 1198s ⇒ the final step had ≈2 seconds of budget. The other 18 gates in the same merge group were all green.

the job was killed on the step AFTER the tests, by its own ceiling. This workflow's own comment at :616 explains the consequence: "the merge queue cannot tell cancelled from failure" — so a PR that passed was dequeued.

⛔ Why this is not this PR's failure, established rather than asserted

  • The test step succeeded. It is not a test failure at all.
  • The killed step, Run built-artifact pins (dist project), is attached to shard 1 only (matrix.shard == 1, :936) and is unrelated to i18n pack keys.
  • Shard 1 runs 18.0–19.6 min across the 14 most recent merge_group CI runs — 11 of 14 sit within 0.4–2.0 min of the ceiling; the longest successful one is 19.6 min. ⇒ the margin is ~24 seconds at its thinnest and this run drifted 3% past it.
  • On this exact commit, shard 1 passed on the pull_request event at ~18m53s two hours earlier, and all 37 checks on this head are green right now.

⇒ filed as objectui#9499 (domain:devx, p2, with a written mechanical trigger to p1). ⛔ Raising timeout-minutes: 20 is ruled out by this file's own standing ruling at :641, and I am not proposing it.

⚠️ One correction on the record: my first suspicion was objectui#9271's --testTimeout=60000. Wrong — that flag is on the coverage lane (timeout-minutes: 40, :1123), and Test (coverage) was skipped in this merge group. It cannot have contributed.

What I am doing about it

Re-queueing once, and only once. That is the single re-run this seat allows itself after establishing a failure is not the PR's — ⛔ it is not a "let's see if it's flaky" retry: the tests are green on this head, the cause is named, and 11 of the last 14 runs of this job finish inside the ceiling.

⛔ If it is dequeued a second time, objectui#9499's trigger (1) fires, it becomes p1, and this PR waits for the CI repair rather than being re-queued a third time. ⛔ No test skipped, ⛔ no ceiling raised, ⛔ no queue bypassed, ⛔ no approval from this seat.

The landing probe registered at 5662899789 is unchanged and still binding — P1–P4 get run on the ACTUAL M/M^ resolved after the merge, whenever it happens.


Generated by Claude Code

@os-try-charles
os-try-charles added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit ef52001 Sep 14, 2026
38 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-8754-retire-dead-pack-keys-round2 branch September 14, 2026 11:55
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.

i18n: retire 25 measured-dead pack keys — the 13 objectui#8701 uncovered, plus the two whole families they belong to

1 participant