Skip to content

fix(mobile): check counted messages with non-literal keys in the plural audit - #8020

Merged
iscekic merged 7 commits into
mainfrom
drain/plural-audit-dynamic-keys
Oct 22, 2026
Merged

iscekic merged 7 commits into
mainfrom
drain/plural-audit-dynamic-keys

Conversation

@iscekic

@iscekic iscekic commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Change

The plural audit (tools/i18n/check-plurals.mjs) promised to check every counted message, but its scanner only matched single-quoted literal keys. Counted calls with a double-quoted or template-literal key were skipped, and counted calls whose key is a variable — t(mcp.view.statusKey, { count }) — were invisible to it entirely. Six such dynamic call sites exist, and through them three counted messages rendered one invariant form for every count: modelChat.mcp.serverToolCount ("1 tools"), profiles.counts.vars ("1 vars"), skills ("1 skills") and commands ("1 cmds").

  • The audit now reads double-quoted and static template-literal keys, records counted calls whose key is a variable expression, and requires each such expression in a reviewed DYNAMIC_COUNTED_KEYS allowlist naming the keys it can produce (each entry cites the descriptor that pins the set). Unlisted variable-key counted calls are a problem of their own.
  • Every key the allowlist names is checked like a literal: an English plural family or a documented NO_AGREEMENT entry.
  • serverToolCount, vars, skills and commands declare their English _one/_other families; the base keys are removed, matching how every other plural family ships.
  • All 86 other catalogs gain exactly the categories their own Intl.PluralRules requires for the four families, with the base translation reused unchanged (languages that do not inflect repeat the same form, the existing house pattern).
  • Invariant status labels and compact suffixes (mcp, varsShort, …) are documented in NO_AGREEMENT as carrying no inflected word.

End-to-end evidence

  • Before the catalog fix, node tools/i18n/check-plurals.mjs --source-only reported 13 problems on the new audit (the four families plus unreviewed dynamic calls); after, it and the full 87-locale run pass: check-plurals: every counted message and every locale declares its plural categories.
  • pnpm --filter kilo-app run check:i18n passes: 87 languages, every catalog matches en.json.
  • pnpm --filter kilo-app run check:plurals passes.
  • Runtime resolution probe through i18next (throwaway vitest, since removed): ru resolves serverToolCount 1→_one ("1 инструмент"), 3→_few ("3 инструмента"), 5→_many ("5 инструментов"); ar resolves 0/1/2/11→_zero/_one/_two/_many; en resolves 1→"1 tool", 5→"5 tools"; profiles.counts.vars 1→"1 var".
  • pnpm --filter kilo-app exec vitest run src/i18n: 16 files, 1612 tests pass, including new tests for double-quoted/template-literal collection, unlisted dynamic calls, and singular selection of the previously broken keys.
  • Mobile typecheck (tsgo --noEmit) passes; lint clean.
  • No screenshot: the affected copy renders inside the MCP settings sheet only when a connected server reports exactly one tool, a state this VM cannot produce; the i18next resolution probe above is the exercised evidence.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: How should the audit handle counted calls whose key is a variable?
    Answer: Reviewed allowlist in the script
    Confidence: 0.72 — the brief offers the allowlist, and the descriptors are there for a reason.
  2. Question: How should catalogs of languages that do not inflect satisfy the per-language report?
    Answer: Same form in every required category
    Confidence: 0.75 — fix the class of the issue; exempting the families would leave the audit's promise broken.
  3. Question: When a counted key gains a family in en.json, what happens to the old unsuffixed base key?
    Answer: Remove base keys
    Confidence: 0.80 — replace old paths instead of keeping them alongside.

…al audit

The plural audit only matched single-quoted literal keys, so counted calls
with a double-quoted or template-literal key were skipped and counted calls
with a variable key were invisible to it. Four such call sites exist in the
chat settings and profile rows; through them, modelChat.mcp.serverToolCount
and the profiles.counts unit words rendered one invariant form for every
count.

The audit now reads double-quoted and static template-literal keys, records
counted calls whose key is a variable expression, and requires each such
expression in a reviewed allowlist that names the keys it can produce. Every
key the allowlist names is checked like a literal one.

serverToolCount, vars, skills and commands declare their English plural
families; invariant status labels and compact suffixes are documented as
carrying no inflected word. Every other catalog gains the categories its own
plural rules require, reusing the base translation unchanged.
@iscekic iscekic added drain Work item from the findings drain janitor:experience-design Experience-design janitor work item labels Oct 19, 2026
The test pinned the count-invariant output the audit now prevents: one
command renders the _one form.
Comment thread tools/i18n/check-plurals.mjs Resolved
Comment thread apps/mobile/src/i18n/locales/te.json Resolved
Comment thread tools/i18n/check-plurals.mjs Resolved
@kilo-code-bot

kilo-code-bot Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change is a two-line test assertion pinning the unlisted-dynamic-call path, plus a merge of main that preserved the audit's dynamic-key logic and every locale plural fix; no new defects found.

Assumptions: [INFERENCE] The merge's locale and script resolution was verified against main and the pre-merge branch tip, but the full 87-catalog matrix was not re-executed because this review is read-only and execution is disabled.

Files Reviewed (6 files, incremental scope)
  • tools/i18n/check-plurals.mjs - no issues; merge combined main's findCountlessFamilies refactor with the branch's findUnlistedDynamicCalls/DYNAMIC_COUNTED_KEYS checks without dropping either
  • apps/mobile/src/i18n/plural-families.test.ts - no issues; new findUnlistedDynamicCalls(root) assertion matches the implementation and the fixture
  • apps/mobile/src/i18n/locales/ar.json - targeted check: prior _many accusative and _other singular fixes still present
  • apps/mobile/src/i18n/locales/gu.json - targeted check: skills_other plural retained
  • apps/mobile/src/i18n/locales/kn.json - targeted check: vars_other plural retained
  • apps/mobile/src/i18n/locales/{lv,lt}.json - targeted check: _zero/_other/_few forms retained through the merge

All previously raised findings are resolved at ff87974e1; no findings remain.

Previous Review Summaries (4 snapshots, latest commit 1229dbb)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 1229dbb)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit fixes all four outstanding plural findings in Arabic, Gujarati, and Kannada; no new issues were introduced.

Files Reviewed (3 files)
  • apps/mobile/src/i18n/locales/ar.json - previous findings resolved (_other singular restored, _many accusative restored)
  • apps/mobile/src/i18n/locales/gu.json - previous finding resolved (skills_other plural restored)
  • apps/mobile/src/i18n/locales/kn.json - previous finding resolved (vars_other plural restored)

Previous review (commit 818c8d9)

Status: 4 Issues Found | Recommendation: Address before merge

Executive Summary

The Latvian and Lithuanian corrections landed, but Gujarati skills_other and Kannada vars_other still repeat the singular for counts above 1, and Arabic _other remains plural for 100+ counts.

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/i18n/locales/gu.json 3553 skills_other is still કૌશલ્ય, so 2+ renders 2 કૌશલ્ય; restore કૌશલ્યો
apps/mobile/src/i18n/locales/kn.json 3555 vars_other is still ಅಸ್ಥಿರ, so 2+ renders 2 ಅಸ್ಥಿರ; restore ಅಸ್ಥಿರಗಳು
apps/mobile/src/i18n/locales/ar.json 3484 _other (100+) is still plural أدوات; Arabic keeps the noun singular after 100, matching file_other/cent_other

SUGGESTION

File Line Issue
apps/mobile/src/i18n/locales/ar.json 3483 _many (11–99) lost the accusative tanween the previous commit and the rest of the catalog use (ملفًا, دولارًا)
Files Reviewed (5 files)
  • apps/mobile/src/i18n/locales/ar.json - 2 issues
  • apps/mobile/src/i18n/locales/gu.json - 1 issue
  • apps/mobile/src/i18n/locales/kn.json - 1 issue
  • apps/mobile/src/i18n/locales/lt.json - no issues
  • apps/mobile/src/i18n/locales/lv.json - no issues

Fix these issues in Kilo Cloud

Previous review (commit 4aef751)

Status: 5 Issues Found | Recommendation: Address before merge

Executive Summary

The audit script changes and the three prior findings are resolved, but five catalogs changed _other to the wrong grammatical category, so common counts render the wrong noun form in Latvian, Lithuanian, Kannada, and Gujarati.

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/i18n/locales/gu.json 3550 skills_other repeats the singular, so counts above 1 render 2 કૌશલ્ય; restore કૌશલ્યો
apps/mobile/src/i18n/locales/kn.json 3547 vars_other repeats the singular, so counts above 1 render 2 ಅಸ್ಥಿರ; restore ಅಸ್ಥಿರಗಳು
apps/mobile/src/i18n/locales/lv.json 3589 vars_other/skills_other/commands_other now hold the genitive _zero form, wrong for the 2-9 other category
apps/mobile/src/i18n/locales/lt.json 3398 serverToolCount_other now holds the _few nominative form, wrong for 0 and 10-20, which take genitive plural

SUGGESTION

File Line Issue
apps/mobile/src/i18n/locales/ar.json 3480 Arabic other covers 100+, where the noun stays singular; the new plural forms (أدوات, and the same in vars/skills/commands) do not match the catalog's own file_other/cent_other pattern
Files Reviewed (19 files)
  • apps/mobile/src/i18n/locales/af.json - no issues
  • apps/mobile/src/i18n/locales/am.json - no issues
  • apps/mobile/src/i18n/locales/ar.json - 1 issue
  • apps/mobile/src/i18n/locales/be.json - no issues
  • apps/mobile/src/i18n/locales/et.json - no issues
  • apps/mobile/src/i18n/locales/gu.json - 1 issue
  • apps/mobile/src/i18n/locales/ha.json - no issues
  • apps/mobile/src/i18n/locales/kn.json - 1 issue
  • apps/mobile/src/i18n/locales/lt.json - 1 issue
  • apps/mobile/src/i18n/locales/lv.json - 1 issue
  • apps/mobile/src/i18n/locales/ml.json - no issues
  • apps/mobile/src/i18n/locales/ru.json - no issues
  • apps/mobile/src/i18n/locales/si.json - no issues
  • apps/mobile/src/i18n/locales/so.json - no issues
  • apps/mobile/src/i18n/locales/sq.json - no issues
  • apps/mobile/src/i18n/locales/sw.json - no issues
  • apps/mobile/src/i18n/locales/te.json - no issues
  • apps/mobile/src/i18n/locales/ur.json - no issues
  • tools/i18n/check-plurals.mjs - no issues

Fix these issues in Kilo Cloud

Previous review (commit a9af7cb)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
tools/i18n/check-plurals.mjs 407 The mcp.view.statusKey and kilo.statusKey allowlists omit modelChat.mcp.unreachable, which retryable() can produce, so the audit never checks that counted message
apps/mobile/src/i18n/locales/te.json 3313 The _one entry reuses the plural base, so count 1 still renders plural copy; the same reuse appears in ml, ur, si, am and sq for all four families

SUGGESTION

File Line Issue
tools/i18n/check-plurals.mjs 344 Dynamic-key expressions are only trimmed despite the documented whitespace normalization, so a reflowed call no longer matches its allowlist entry
Files Reviewed (90 files)
  • tools/i18n/check-plurals.mjs - 2 issues
  • apps/mobile/src/i18n/plural-families.test.ts - no issues
  • apps/mobile/src/lib/profile-count-labels.test.ts - no issues
  • apps/mobile/src/i18n/locales/en.json - no issues
  • apps/mobile/src/i18n/locales/*.json (86 translated catalogs) - 1 issue (te:3313; same pattern in ml/ur/si/am/sq)

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 84.9K · Output: 12K · Cached: 1.6M

Review guidance: REVIEW.md from base branch main

Three review findings:

- The MCP status allowlists omit modelChat.mcp.unreachable, which the
  McpStatusKey union includes and retryable() returns for failures other
  than the credential refusal; both lists now name it.
- The dynamic-key expression is documented as whitespace-normalized but
  only trimmed; a wrapped call would record a key the allowlist never
  matches. Runs of whitespace now collapse before recording.
- Sixteen locales rendered the plural base for count 1 (Telugu, Malayalam,
  Urdu, Sinhala, Amharic, Albanian among them), leaving the one-tools bug
  this change fixes in those catalogs. Their singular entries now carry the
  natural singular noun, and the plural base stays verbatim in the category
  that carries it.
Comment thread apps/mobile/src/i18n/locales/gu.json Resolved
Comment thread apps/mobile/src/i18n/locales/kn.json Resolved
Comment thread apps/mobile/src/i18n/locales/lv.json Resolved
Comment thread apps/mobile/src/i18n/locales/lt.json Resolved
Comment thread apps/mobile/src/i18n/locales/ar.json Resolved
…nian and Arabic

The first plural pass put the shipped form in the wrong category for five
languages: Gujarati and Kannada lost their plural in the residual category,
Latvian and Lithuanian took the genitive that belongs to the zero and
ten-to-twenty counts, and Arabic replaced the singular that 100 and above
keeps. Each catalog now assigns the shipped form to its own category and
derives the rest around it.
Comment thread apps/mobile/src/i18n/locales/gu.json Resolved
Comment thread apps/mobile/src/i18n/locales/kn.json Resolved
Comment thread apps/mobile/src/i18n/locales/ar.json Resolved
Comment thread apps/mobile/src/i18n/locales/ar.json Resolved
…rabic

Gujarati skills and Kannada variables keep their plural in the residual
count category, and Arabic restores the singular noun for the hundreds and
the accusative ending for eleven through ninety-nine.
@iscekic iscekic added merge:human Substantive functional risk requires human review. merge:bot Bot-owned review; merge when ready once readiness passes and a review approves. and removed merge:human Substantive functional risk requires human review. labels Oct 19, 2026
@iscekic
iscekic added this pull request to the merge queue Oct 21, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 21, 2026
@iscekic iscekic removed the merge:bot Bot-owned review; merge when ready once readiness passes and a review approves. label Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drain Work item from the findings drain janitor:experience-design Experience-design janitor work item merge:bot Bot-owned review; merge when ready once readiness passes and a review approves.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants