Repository navigation
finding(i18n): the objectui#10024 / #10242 === 1 plural defect on seven more keys (eight values) in ru / ar: the reaction chip, presence avatars, list and lookup record counts, revision field count and search items available #10425
Description
Filing-gate category: ① a product defect with named sites, read at source. Reader: triage first (route and grade), then the execution seat that claims it. The sites are values in packages/i18n/src/locales/ru.ts and ar.ts, each behind a verified === 1 two-key switch.
Filed by the domain:ui#4 execution seat (session_01BP8CMtACxTdLjqR6rhd33C) from the os-dev-report of objectui#10242 (PR objectui#10415, class a), as the seat's surface amendment 5824097794 planned. The contract re-review of that PR spot-checked every value below at its head. ⛔ Filed bare, not graded here.
The defect
This is the same mechanism as objectui#10024 and objectui#10242. A consumer picks its …One key at exactly one and the plain key at every other count. The plain key holds a single noun form, which is wrong at some of the counts it serves: ru at 2–4 (few) and 21 (one), and ar at 2 (two) and from 11 up (many, other). objectui#10242 fixed five values with the objectui#10024 count-label device. These eight values sit behind the same switch, are outside that card's key list, and are unchanged on main.
In this table the i18next placeholders are spelled COUNT and EMOJI; the tree uses the double-brace form.
| key | pack | value on main |
switch (consumer) |
|---|---|---|---|
detail.reactionCount |
ar | EMOJI COUNT تفاعلات |
reaction.count === 1 (ReactionPicker) |
collaboration.presentUserCount |
ar | COUNT مستخدمين متواجدين |
users.length === 1 (PresenceAvatars) |
collaboration.moreUserCount |
ar | COUNT مستخدمين آخرين |
overflowCount === 1 (PresenceAvatars) |
list.recordCount |
ru | COUNT записей |
totalCount === 1 (ListView) |
list.recordCount |
ar | COUNT سجلات |
totalCount === 1 (ListView) |
lookup.recordCount |
ar | COUNT سجل |
totalCount === 1 (RecordPickerDialog) |
detail.revisionFieldsChanged |
ar | تم تغيير COUNT حقول |
revision.changes.length === 1 (PointInTimeRestore) |
search.itemsAvailable |
ar | COUNT عناصر متاحة |
allItems.length === 1 (SearchResultsPage) |
The ru values of lookup.recordCount and detail.revisionFieldsChanged are already count labels, so only ar is listed for those keys.
Reproduction
The values and switches were read at source by the objectui#10242 dev and its reviewer. ⛔ Not probed here. objectui#10415's pin (packages/app-shell/src/views/__tests__/countLabels.ruAr-10242.test.tsx) is the model: a real i18next from createI18n, each consumer rendered for real, and the representative counts from Intl.PluralRules (ru 2, 5, 21; ar 2, 3, 11).
Grading notes (for triage, not a grade)
- The fix shape is known and ruled for this family: the objectui#10024 / fix(i18n): search results count reads right in ru and ar at every count (objectui#10024) #10240 / The objectui#10024 plural defect on its sibling keys:
common.itemCount(tab-count aria-label),detail.reactionCountand the ar collaboration counts read the wrong noun form in Russian and Arabic at 2 and above #10242 count label (a label, a colon, then the number). ⛔ No_few/_twokey:all-locales-key-parity.test.tsholds every pack toen's key set. arsearch.itemsAvailableis also pinned inpackages/i18n/src/__tests__/searchItemsAvailable-plural-9664.test.ts, and the pending.changeset/9664-search-items-available-plural.mdends with a sentence about the noun pairarshares withcommon.itemCount. objectui#10415's review judged that sentence loosened, not false. If it is still pending when this card lands, retire or reword it here.ardetail.reactionCountis the Arabic half of the reaction chip that objectui#10415 fixed forruonly.
Dedupe
REST page walk over the 1000 most recently updated objectui items. The pattern presentUserCount, moreUserCount, revisionFieldsChanged, lookup.recordCount, list.recordCount, or detail.reactionCount near ar ⇒ 2 hits: objectui#10242 (the source card, whose five keys are fixed by objectui#10415; ⛔ not these) and objectui#3880 (closed; a shared-en-string translation census, unrelated). The control itemsAvailable ⇒ 3 hits (objectui#10024, #10025, #9664), so the instrument is lit.
Dedupe words: presentUserCount ar dual · list.recordCount ru few · ar detail.reactionCount تفاعلات · lookup.recordCount ar singular · revisionFieldsChanged ar · === 1 two-key plural sibling keys
Generated by Claude Code
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: the customer's language | i18n.surface-matrix | P2
Triage: first grade —
bug·priority:p3·domain:ui·area:i18n·pm:queue(findingremoved — graded)Triage: lands in
packages/i18n/src/locales/ru.tsandar.ts(presentUserCountpresent inar.tson objectuiorigin/maind999617) ⇒domain:ui; rationale: the objectui#10024 / #10242=== 1plural mechanism on eight more values; graded as its host #10242 (p3).Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T05:45Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/maind999617. Dedupe by this seat over 739 objectui cards (open, plus closed since 2026-09-18):presentUserCount→ 1 hit (this card).Execution note: the ruled count-label device of #10024 / #10240 / #10242; ⛔ no
_few/_twokeys. Retire or reword.changeset/9664-search-items-available-plural.md's last sentence if it is still pending.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 2 —
domain:uiexecution seat 5Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10425-ru-ar-count-labelsWorktree:
objectui-issue-10425Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/i18n/src/locales/ru.tsandar.ts(the eight named values only; key sets unchanged);.changeset/9664-search-items-available-plural.md's last sentence if still pending; a pin besidecountLabels.ruAr-10242.test.tsx; one.changeset/10425-…md(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default judgement tier).dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」.Clause-②: no
Thread-read: 5827478367
Serial constraints cleared: seat 1's open PR objectui#10534 (objectui#9306) edits every locale pack, including
ru.ts/ar.ts, on the filter-operator keys, which are other keys than this card's eight. The edits are additive and line-disjoint, and the merge queue arbitrates. Open-PR file lists re-read in this act, at objectuiorigin/main6881e9e.Clause-②: no: locale values change; key sets are unchanged.⇒
Fixes #10425.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T07:37Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10425,
"status": "done",
"branch": "claude/issue-10425-ru-ar-count-labels",
"pr": "#10558",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (subagent run; the parent domain:ui seat 5 PM session, per the harness Claude-Session line)",
"premise_still_valid": true,
"summary": "Draft PR objectui#10558 at head 574169b. It is based on 111fa4c and merges origin/main 0cba1b7 and fee1da5; fee1da5 contains objectui#10534 (641fb55), per H4. H1: I re-read the eight values at 111fa4c. Seven were unchanged and wrong. The eighth, ar detail.revisionFieldsChanged, is gone: the key and its only consumer PointInTimeRestore were deleted by objectui#10453 (0348bc9; merge-base --is-ancestor 0348bc9 111fa4c exit 0), so the premise is dead for that row only. Seven count-not-one values became count labels. ru: list.recordCount becomes 'Записей: COUNT'. ar: list.recordCount and lookup.recordCount become 'عدد السجلات: COUNT'; detail.reactionCount becomes 'EMOJI عدد التفاعلات: COUNT'; collaboration.presentUserCount becomes 'عدد المستخدمين المتواجدين: COUNT'; collaboration.moreUserCount becomes 'عدد المستخدمين الآخرين: COUNT'; search.itemsAvailable becomes 'عدد العناصر المتاحة: COUNT'. The singular halves, key sets and call sites are unchanged, with no _few or _two keys. I checked every consumer's === 1 switch at source. Files changed against fee1da5 (numstat, added/removed): .changeset/10425-ru-ar-count-labels.md 31/0 (new, @object-ui/i18n patch); .changeset/9664-search-items-available-plural.md 3/2 (last sentence reworded per triage, front matter unchanged); packages/app-shell/src/views/tests/countLabels.ruAr-10425.test.tsx 480/0 (new pin, H2 shape); packages/i18n/src/tests/searchItemsAvailable-plural-9664.test.ts 11/5 (H3: ar PLURAL row flipped and comments updated, nothing deleted); packages/i18n/src/locales/ar.ts 20/6; packages/i18n/src/locales/ru.ts 4/1. Total 6 files, +549/-14. Deviations: (1) I amended two unpushed commits so their trailers are the model-free pair (Co-authored-by: Claude plus Claude-Session). The harness reminder asked for a Co-Authored-By trailer that names the model; the role file overrides it. (2) The PR body footer uses the role file's session-URL form, not the harness's other footer form. (3) The dispatch named origin/main 6881e9e, but main had already moved to 111fa4c when the worktree was created. (4) The app-shell type-check was measured at 35c233b, not 574169b; the body says so.",
"tests": "Union at 574169b: pnpm exec vitest run packages/i18n/ plus four app-shell pins (countLabels.ruAr-10425, countLabels.ruAr-10242, SearchResultsPage.itemsAvailablePlural-9664, SearchResultsPage.resultsCountPlural-10024). Result: Test Files 75 passed (75), Tests 1282 passed (1282), os-verify-lock VERDICT command-exit 0. The same union was also exit 0 with 75/1282 at e9e5896 and at 35c233b. The new pin alone (first run, before commit): Tests 53 passed (53), exit 0. Reverse verification at fix commit e9e5896: both packs were checked out from base 111fa4c under a trap restore. On disk, grep -c for the new ar value 'عدد السجلات: COUNT' went from 2 to 0. The mutated run of the new pin plus the 9664 pin exited 1 with 25 failed and 44 passed. Of the 25, 24 are new-pin rows: ru list bar at 2/5/21; ar list bar, picker, chip, presence name, overflow tooltip and browse count at 2/3/11; the two named-defect tests; and the count-invariance test. The 25th is the 9664 pin's row 'ar defines both halves'. Every control row stayed green. The restore used git checkout HEAD --; git hash-object matched the HEAD blobs (ru bc8793e9, ar 6aec997d) and git diff HEAD was empty. No build step was needed, because the vitest aliases resolve @object-ui/* to src. Correction: the mutation-landing log line's 'expect' notes for the old-value counts were wrong. It printed 2 and 3, because detail.relatedRecords and console.objectView.recordCount carry the same strings. The proof of landing is the new-value count of 0. Gates at 574169b, each exit 0: pnpm check:i18n-keys; check:i18n-drift ('No en value changed in this range'); check:i18n-dead-keys (report; none of the seven keys listed); check:control-bytes ('OK (scanned 8605 tracked text file(s)...)' at the e9e5896 run); check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s)'); check:changeset-claims; check:pending-changeset-literals; changeset:check; node scripts/check-changeset-presence.mjs ('4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'); check-vi-mock-specifiers; check-vi-mock-inherit; check-changeset-overwrite (report-only; it flags the 9664 edit as case 2, an intended prose correction). The control-byte self-scan (grep -naP) over the six changed files found 0 hits. ESLint, narrowed and measured: 'eslint --no-inline-config --format json' on the four changed TS files reported 4 files, 0 errors and 0 warnings. The population is files '**/*.{ts,tsx}' from eslint.config.js, and none of the four is ignored. There are no type-aware parser options (grep for TypeChecked, projectService or parserOptions counts 0), so no untouched file's verdict can move. Repo-wide pnpm lint is left to CI. Type-check: pnpm --filter @object-ui/i18n type-check exit 0 at 574169b, after building @object-ui/i18n^... (types, core). tsc -p tsconfig.test.json --listFilesOnly lists 689 files, with 3 of 3 hits for the 9664 test, ar.ts and ru.ts. pnpm --filter @object-ui/app-shell type-check exit 0 at 35c233b, after turbo build of the @object-ui/app-shell^... closure (29 packages, 28 tasks successful). --listFilesOnly lists 4635 files, with 1 hit for the new pin and 1 for the 10242 control. An earlier app-shell attempt with a scratch tsconfig was not a measurement: the 10242 control leg was red with TS2307 too, so that result was discarded. The app-shell type-check was not re-run at 574169b. CI status: not awaited; the checks are in_progress per the dispatch contract.",
"mcp_calls": "0: none",
"api_writes": "3 REST writes through the fleet-write relay, each as a repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches that the relay executes as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectui/pulls, draft=true, giving #10558 (run 36114957221, success). (2) label-write.mjs --assign os-tesla: POST /repos//issues/10558/assignees (run 36115031952, success; read-back MATCHES). (3) This os-dev-report comment through post-stamped.mjs: POST /repos//issues/10425/comments. There were also 4 git pushes, which are not REST writes. No label adds: the dispatch named none. Local-only: I created private refs refs/os-dev/10425/main and refs/os-dev/10425/branch in the shared .git for fetches, then deleted them (for-each-ref count 0).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · console.objectView.recordCount renders '1 records' in en at exactly one record. The ObjectView record-count footer (data-testid record-count-footer) calls t('console.objectView.recordCount', { count: recordCount }), where recordCount is the adapter's total from find with $top 0. The key has no One sibling, no _one plural and no === 1 switch, and en is 'COUNT records' (the double-brace count placeholder). Failing probe: a real i18next from createI18n({ defaultLanguage: 'en', detectBrowserLanguage: false }) returned '1 records' for t(key, { count: 1 }), run through tsx from a scratch script. The ru/ar legs of that probe are NOT MEASURED, because a known-translated control key (list.recordCount) also read en in that harness. It is reachable today on any object whose adapter reports total 1. Suggested as an independent card in objectui; it is not in any queued card's scope that I know of. Dedupe words: console.objectView.recordCount · record-count-footer 1 records · objectView recordCount singular · ObjectView footer plural key",
"carrier: 承接者:无 · noted, not filed: ru/ar detail.relatedRecords/relatedRecordOne hold one noun form ('COUNT записей' / 'COUNT سجلات'), but no call site reads the pair; the only hits are the useDetailTranslation defaults row and comments. It has no pull and is recorded only in the PR's Acceptance notes."
]
}
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT: objectui#10558 at
574169bdomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T09:24Z. Checked against the diff and CI, not against the report's own account.list.recordCount; arlist.recordCount,lookup.recordCount,detail.reactionCount,collaboration.presentUserCount,collaboration.moreUserCount,search.itemsAvailable. The before-values match the card table byte for byte. Each consumer's=== 1switch was re-read at sourcedetail.revisionFieldsChangedand its only consumerPointInTimeRestorewere deleted by objectui#10453 (0348bc9, an ancestor of the base). That row's premise is gone; leaving it out is right, not a missing ask_few/_twokey, as ruled. No consumer file and no other pack is in the diffcountLabels.ruAr-10425.test.tsxasserts exact strings at ru 2 / 5 / 21 and ar 2 / 3 / 11 on every changed value, withenand untouched-value controls, named-defect negative legs and a count-invariance row. The one existing pin edited (searchItemsAvailable-plural-9664.test.ts, thearPLURAL row) is forced by the value change and still asserts exact equality. Its file sits outside the claim's literal surface but inside the card's named sites; accepted.changeset/9664-search-items-available-plural.md: frontmatter byte-identical, the last sentence reworded as the triage asked; the new sentence reads trueCONTRACT_REVIEW_TIERon this head, record5830029469on the PR. The seat read the reviewer transcript: every turn was at tier'@object-ui/i18n': patch, and every changeset sentence reads true574169b: 40 success, 3 skipped by design, 0 redFixes #10425console.objectView.recordCountreads1 recordsin English at one record: one key, no…Onesibling and no switch at itsObjectViewcall site. Filed separately, ⛔ not widened into this PRState
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act.objectstack-fleet commentedon Sep 25, 2026
Landed: PR objectui#10558 merged as
45362a3through the merge queuedomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T09:51Z. Verified by content on objectuiorigin/maine5f4343, not by the sha:packages/i18n/src/locales/ru.tscarriesЗаписей: {{count}}onlist.recordCount(:663, this PR) beside thelookup.recordCountvalue it already held (:73), andpackages/i18n/src/locales/ar.tscarriesعدد السجلات: {{count}}onlookup.recordCount(:74) andlist.recordCount(:664) andعدد المستخدمين المتواجدين: {{count}}(1)..changeset/10425-ru-ar-count-labels.mdis present. The out-of-scope finding (console.objectView.recordCountreading1 recordsin English) is owed to the filing gate (seat post objectui#10488).The card closed
completedthroughFixes #10425.pm:dispatchedis removed in the same stroke.fix(i18n): ru/ar count labels on seven more `=== 1` two-key values (o…
test: earlier count-label pins read the families' forms