Found while working the objectui#4730 dead-key batch (PR #6662). Filed unassigned as a sub-issue of that umbrella, because it is a defect in the umbrella's instrument rather than in its backlog of keys.
The defect
scripts/check-i18n-dead-keys.mjs reported five live keys at its strongest CONFIRMED tier. They were caught only by reading the consumer by hand; nothing in the tool's output hinted anything was missed.
Measured on 813bf8323:
console.loadingSteps.connectingconsole.loadingSteps.loadingConfigconsole.loadingSteps.preparingWorkspaceconsole.error.connectionFailedconsole.error.checkServer
All five are read by packages/app-shell/src/chrome/LoadingScreen.tsx.
Why both legs of the evidence standard miss it
LoadingScreen.tsx is bootstrap-critical UI: it must render before i18n loads, which is exactly when the server is unreachable. Its own comment says so, and it deliberately does not call useObjectTranslation. Instead it imports the packs and reads them as plain object properties:
import{enasenLocale,builtInLocales}from'@object-ui/i18n';// ...conststrings=getStartupStrings();strings.loadingSteps.connecting// = console.loadingSteps.connectingstrings.error.connectionFailed// = console.error.connectionFailed- The AST pass classifies
t() / tt() call sites. There is no call, so nothing is visited. - The text safety net greps the full dotted key. The full dotted key is never spelled: the namespace segment is bound to a local variable, so the source contains
strings.loadingSteps.connecting and never console.loadingSteps.connecting.
So the key is invisible to both, and lands in CONFIRMED — the tier documented as "no call site and no textual occurrence anywhere else in the repo", which reads as the safest thing to delete. Deleting this family ships a blank splash screen in ten locales on precisely the server-down boot the screen exists to explain.
The blind spot is a class, not these five keys
Any consumer that reaches a pack through a reference whose variable name replaces the namespace prefix is invisible the same way. Today the pack-object importers outside packages/i18n are:
packages/app-shell/src/chrome/LoadingScreen.tsx (the case above)packages/app-shell/src/console/ai/outboundAgentText.ts — indexes console.ai dynamically (ai?.[key]). Its four keys happen to land in NEEDS-REVIEW because the property names appear as literals in a nearby type union, so the net catches them by luck, not by design.packages/plugin-grid/demo/main.tsx and demo/bulk-actions.tsx — whole-pack resources only, no per-key reads.
The set is small today, which is what makes this cheap to close now.
Suggested remedy
Add a property-chain leg to the text safety net: alongside the full dotted key, probe the tail chain (.loadingSteps.connecting). Validated on this batch with both controls before being trusted:
- the five live keys above: detected (1 hit each);
console.error.serverUnreachable and console.error.timeout, which genuinely have no pack reader: 0 hits.
So the leg discriminates rather than demoting everything. Note it is only meaningful for keys of three or more segments — a two-segment key yields a one-word tail (.no, .ok, .empty) that is far too generic. For two-segment keys the sound check is the enumerated importer set above, which is what PR #6662 used.
A cheaper partial mitigation, already in place: PR #6662's retirement pin names the nine bootstrap strings, which gives them a textual footprint and demotes them from CONFIRMED to NEEDS-REVIEW in the tool's own output. That protects this one family only, and by side effect rather than by design.
Why this is filed separately from the umbrella
objectui#4730 tracks keys; this tracks the tool every future round of it depends on. The umbrella's remaining trims (search, table, report, form, appDesigner) will each be triaged against this same CONFIRMED tier, so the false-positive class is live work, not history.
Back-links: objectui#4658 (the sweep mechanism and its three-legged evidence standard), objectui#4730 (the backlog), PR #6662 (where this was measured).
Generated by Claude Code
Generated by Claude Code
Found while working the objectui#4730 dead-key batch (PR #6662). Filed unassigned as a sub-issue of that umbrella, because it is a defect in the umbrella's instrument rather than in its backlog of keys.
The defect
scripts/check-i18n-dead-keys.mjsreported five live keys at its strongest CONFIRMED tier. They were caught only by reading the consumer by hand; nothing in the tool's output hinted anything was missed.Measured on
813bf8323:console.loadingSteps.connectingconsole.loadingSteps.loadingConfigconsole.loadingSteps.preparingWorkspaceconsole.error.connectionFailedconsole.error.checkServerAll five are read by
packages/app-shell/src/chrome/LoadingScreen.tsx.Why both legs of the evidence standard miss it
LoadingScreen.tsxis bootstrap-critical UI: it must render before i18n loads, which is exactly when the server is unreachable. Its own comment says so, and it deliberately does not calluseObjectTranslation. Instead it imports the packs and reads them as plain object properties:t()/tt()call sites. There is no call, so nothing is visited.strings.loadingSteps.connectingand neverconsole.loadingSteps.connecting.So the key is invisible to both, and lands in CONFIRMED — the tier documented as "no call site and no textual occurrence anywhere else in the repo", which reads as the safest thing to delete. Deleting this family ships a blank splash screen in ten locales on precisely the server-down boot the screen exists to explain.
The blind spot is a class, not these five keys
Any consumer that reaches a pack through a reference whose variable name replaces the namespace prefix is invisible the same way. Today the pack-object importers outside
packages/i18nare:packages/app-shell/src/chrome/LoadingScreen.tsx(the case above)packages/app-shell/src/console/ai/outboundAgentText.ts— indexesconsole.aidynamically (ai?.[key]). Its four keys happen to land in NEEDS-REVIEW because the property names appear as literals in a nearby type union, so the net catches them by luck, not by design.packages/plugin-grid/demo/main.tsxanddemo/bulk-actions.tsx— whole-packresourcesonly, no per-key reads.The set is small today, which is what makes this cheap to close now.
Suggested remedy
Add a property-chain leg to the text safety net: alongside the full dotted key, probe the tail chain (
.loadingSteps.connecting). Validated on this batch with both controls before being trusted:console.error.serverUnreachableandconsole.error.timeout, which genuinely have no pack reader: 0 hits.So the leg discriminates rather than demoting everything. Note it is only meaningful for keys of three or more segments — a two-segment key yields a one-word tail (
.no,.ok,.empty) that is far too generic. For two-segment keys the sound check is the enumerated importer set above, which is what PR #6662 used.A cheaper partial mitigation, already in place: PR #6662's retirement pin names the nine bootstrap strings, which gives them a textual footprint and demotes them from CONFIRMED to NEEDS-REVIEW in the tool's own output. That protects this one family only, and by side effect rather than by design.
Why this is filed separately from the umbrella
objectui#4730 tracks keys; this tracks the tool every future round of it depends on. The umbrella's remaining trims (
search,table,report,form,appDesigner) will each be triaged against this same CONFIRMED tier, so the false-positive class is live work, not history.Back-links: objectui#4658 (the sweep mechanism and its three-legged evidence standard), objectui#4730 (the backlog), PR #6662 (where this was measured).
Generated by Claude Code
Generated by Claude Code