feat(i18n)!: retire 23 measured-dead pack keys, two families whole (objectui#8754) - #9487
Conversation
…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
✅ Console Performance Budget
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
Size Limits
|
✅ Console Performance Budget
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
Size Limits
|
CI green on the current head — and the landing probe, written BEFORE the merge
The CI reading, with a control that fires
32 + 3 + 0 + 1 = 36 ✓ (the last before shard 1 landed). ⭐ CONTROL, same instrument, same call shape, same minute — the identical File surface, verified independently of the PR body14 files: 10 locale packs at exactly
|
| # | 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
⛔ Dequeued at 11:22:13Z — ⭐ the tests PASSED. Root-caused, ⛔ not called a flake, and re-queued once.
What actually happenedMerge group
Job wall clock 20m14s against ⇒ the job was killed on the step AFTER the tests, by its own ceiling. This workflow's own comment at ⛔ Why this is not this PR's failure, established rather than asserted
⇒ filed as objectui#9499 (
What I am doing about itRe-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 Generated by Claude Code |
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-keyswas re-run on this branch's own base,ff1d5ea8d1, and the deletion is what it confirms today.Its verdict, quoted from its own output:
The population named in words: 3010 keys defined by the
enpack (the ten packs are parity-identical, whichall-locales-key-parity.test.tsseparately 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.rejectandmarketplace.pricing.freeare 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:
approvalsholds exactly 6 members andmarketplace.pricingexactly 6, in every pack. All 12 are candidates ⇒ no member has a call site.approvals.*— probe and control in the same command, overpackages/ apps/ examples/ e2e/ content/ scripts/minus the ten locale packs (which define every key by construction):approvals.(approve|approveSuccess|comment|reject|rejectSuccess|rejectConfirm)at key boundarypackages/app-shell/CHANGELOG.md:6161— changelog prose about a past change. Zero source hits.approvalsInbox., same command shapeDeclaredActionsBar.tsx:230/236/241,approverIdentity.ts:365/373, …approvalsInboxhitting whileapprovals.does not is the reading the card predicted.marketplace.pricing.*:marketplace.pricing.at key boundarypackages/i18n/src/__tests__/untranslated-identity-4376.test.ts:105— a pin-test allowlist entryt()/tt()call whose key mentionspricingat allpricinganywhere inpackages/app-shell/src/console/marketplace/marketplace.category., same command shapeMarketplacePackagePage.tsx:654,MarketplacePage.tsx:185t()call whose key mentionscategorymarketplace.category.is a collected dynamic template head, which is exactly why none of that family was ever a candidate — and whymarketplace.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.tsasserts, 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.helpTooltipforsidebar.help,home.starredApps.titleforhome.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 (3aab235a78→de6dff3fa1) and by the leaf spelling going0 → 1: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
trapand the restore verified by state, not exit code: on-disk hash equals theHEADblob,git diff HEADempty,git statusclean.All-locales key parity — before and after
Measured on two real trees, not inferred.
ff1d5ea8d1(this branch's base, in its own worktree)ebcbb22e5fParity passes on both sides; the
+1 file / +5 testsis 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 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,homeandworkspacenamespaces, and every one of them is CONFIRMED-dead itself today.Census, before → after, with every number accounted for
ff1d5ea8d1)ebcbb22e5f)en)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 = 98and239 − 2 = 237, which is what the run prints.Bytes — re-measured, ⛔ no budget constant moved
The ruling asks for the⚠️ That chunk no longer exists: objectui#7479 made nine of the ten catalogues lazy and re-keyed the ceiling to
i18n-localeschunk figure.i18n-locale-en. Reported against the successor, from two real console builds:i18n-locale-enchunkcheck:eager-closuregreen on both trees. ⛔PER_CHUNK_GZIP_CEILINGS,PER_CHUNK_BASELINEandMAX_EAGER_CLOSURE_GZIP_BYTESare untouched — this PR changes no file underscripts/.Gates run
pnpm --filter @object-ui/i18n testpnpm --filter @object-ui/i18n type-checktsc --noEmit+ test tsconfigpnpm --filter @object-ui/i18n lintcheck:i18n-keyscheck:i18n-driftenvalues changed in rangecheck:i18n-designer-parityenrow has azhrowcheck:i18n-dead-keyscheck:eager-closurecheck:eager-locale-cataloguescheck:control-bytescheck:test-path-rootscheck:new-line-citationscheck-changeset-presencecheck-changeset-no-majormajordeclaredgates_weakened:NONE — no threshold lowered, no ceiling raised, no non-vacuity floor moved (the> 2000floors 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, andpnpm lintisturbo run lint(per-package), whose@object-ui/i18nleg is the row above.Changeset — measured, not assumed
Owed, and
check-changeset-presencesaid so in its own words.@object-ui/i18nis published (privateunset,v17.6.0) and in the 40-package fixed release group, and this PR changes 12 files under itssrc/..changeset/8754-dead-pack-keys-retired.mdlists 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. Markedminorper this repo's rule that a changeset never declaresmajor.维护者速读(草稿)
改了什么:从十个语言包里删掉 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