Uh oh!
There was an error while loading. Please reload this page.
fix(i18n): ar spells the standalone participle جارٍ pack-wide, not two ways - #6675
Merged
Merged
Conversation
#6610) The `ar` pack wrote the active participle of جرى two ways at once: `جارٍ` on 92 values and `جاري` on 8. One word, two spellings, one code point apart — U+064D (tanwīn kasr, the yāʾ dropped) against U+064A (the yāʾ kept). The 92:8 majority is not the argument. An اسم منقوص declines three ways, so "the 8 are right in their own context" was a live reading and had to be falsified rather than out-voted: - the pack already distinguishes the positions correctly — `جاريًا` twice as the accusative khabar of لا يزال / ما زال, and `الجارية` once as a definite attributive, so `جارٍ` elsewhere is position-sensitive, not a house tic; - none of the 8 was in such a position: all opened their string, none carried ال, and in none was the participle the مضاف — the maṣdar after it is the delayed subject of a fronted indefinite predicate; - both syntactic frames occurred on BOTH sides of the split, five with a word-for-word twin — `grid.refreshing` (`جاري التحديث…`) against `list.refreshing` (`جارٍ التحديث…`) is an exact minimal pair; - none of the 92 followed an accusative governor, from the same detector that did flag all three yāʾ-keeping values. Eight values converged; no key added or removed, no `en` value touched. `ar-participle-orthography-6610.test.ts` makes it a pack-wide invariant instead of an eight-key edit, and pins the three occurrences where the yāʾ is correct so a later sweep cannot flatten a real distinction into a grammatical error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
The first ablation leg reverted one value and tripped the `>= 100` floor at 99, so the failure named "no جارٍ found at all" instead of the offender list — the assertion that names the key and says what to write. The floor is proof of life, not a ratchet: a collapsed pack, a broken import or a matcher that stops matching all take it to 0 or near it, and a single-value regression now belongs to the assertion built to report it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
… pin row Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
Contributor
✅ 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
|
os-sales
marked this pull request as ready for review
August 28, 2026 13:45
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#6610
The
arpack wrote the standalone منقوص active participle of جرى two ways atonce:
جارٍon 92 values andجاريon 8. One word, two spellings, one codepoint apart — U+064D (tanwīn kasr, the yāʾ dropped) against U+064A (the yāʾ
kept). Eight values converged; no key added or removed, no
envalue touched.⛔ The 92:8 majority is NOT why the 8 moved
A distribution cannot rule orthography, and this participle's ending is
genuinely not invariant across syntactic positions. An اسم منقوص declines
three ways:
جارٍجاريًاالجاري/الجاريةSo "the 8 are correct in their own grammatical context" was a live reading and
had to be falsified rather than out-voted. Four measurements did it.
1. The pack already distinguishes the positions — correctly
Three
arvalues keep the yāʾ, and all three are in positions that require it:console.ai.connectionStalledلا يزال العمل جاريًا…empty.appNotAvailableDescription…قد يكون النشر ما زال جارياً.marketplace.installedAdditiveNote…لكن النواة الجارية تبقي التطبيق…A pack that were simply yāʾ-blind could not have got these right. That is the
strongest available evidence that
جارٍelsewhere is a position-sensitivechoice rather than a house tic — and it is the fact that makes reading (2)
below a measurement rather than a preference.
2. Per value: none of the 8 was in such a position
Reported per value, not as a total. All eight are the participle opening the
string (token index 0), so nothing governs them into the accusative; none
carries ال; and in none is the participle the مضاف — the maṣdar after it is the
delayed subject (مبتدأ مؤخر) of a fronted indefinite predicate (خبر مقدم), which
is nominative and indefinite. The annexed reading would turn a status message
into a bare noun phrase with no predication, which is not what the
ensays.grid.loadingجاري تحميل الشبكة…جارٍ تحميل الشبكة…Loading grid…plugin-grid/src/ObjectGrid.tsx:2535grid.refreshingجاري التحديث…جارٍ التحديث…Refreshing…plugin-grid/src/ObjectGrid.tsx:4295chart.loadingجاري تحميل الرسم البياني…جارٍ تحميل الرسم البياني…Loading chart…console.initializingجاري تهيئة التطبيق…جارٍ تهيئة التطبيق…Initializing application…app-shell/src/chrome/LoadingScreen.tsx:87— the headingconsole.loadingSteps.connectingجاري الاتصال بمصدر البياناتجارٍ الاتصال بمصدر البياناتConnecting to data sourceLoadingScreen.tsx:56— boot-step list item 1console.loadingSteps.loadingConfigجاري تحميل الإعداداتجارٍ تحميل الإعداداتLoading configurationLoadingScreen.tsx:57— list item 2console.loadingSteps.preparingWorkspaceجاري تجهيز مساحة العملجارٍ تجهيز مساحة العملPreparing workspaceLoadingScreen.tsx:58— list item 3console.actions.retryingجاري إعادة المحاولة…جارٍ إعادة المحاولة…Retrying…LoadingScreen.tsx:118— the retry buttonThe card's same-screen claim is confirmed from the source:
LoadingScreen.tsxrenders
console.initializingas the heading over the threeconsole.loadingSteps.*as a list, withconsole.actions.retryingon the retrybutton — four of the eight on one screen.
3. ⭐ The minimal pairs settle it
Both syntactic frames occurred on both sides of the split — and five of the
eight had a word-for-word twin already spelled
جارٍ:grid.refreshingجاري التحديث…list.refreshingجارٍ التحديث…— the same two words, one code point apartconsole.loadingSteps.connectingجاري الاتصال…topbar.connection.connectingجارٍ الاتصال…grid.loading/chart.loading/console.loadingSteps.loadingConfigجاري تحميل …list.loadingجارٍ تحميل السجلات…,detail.loadingAttachmentsجارٍ تحميل المرفقات…console.loadingSteps.preparingWorkspaceجاري تجهيز …console.ai.preparingConversationجارٍ تجهيز محادثة جديدةconsole.actions.retryingجاري إعادة …approvalsInbox.resubmittingجارٍ إعادة الإرسال…grid.refreshingagainstlist.refreshingis an exact minimal pair: identicalapart from that one code point. Two spellings of one phrase cannot both be
contextually correct, so possibility 2 fails on this pair alone; the other four
make it a pattern rather than an accident.
4. The 92 needed nothing
Zero of the 92 follow an accusative governor (كان / ما زال / لا يزال / إن …).
That zero is a measurement rather than a silence: the same detector flagged
all three of the yāʾ-keeping values in (1) —
لا يزالandما زالon the twoaccusatives,
لكنon the definite — so it demonstrably fires when there issomething to find. 91 of the 92 open their string; the one exception
(
console.ai.connectionOffline,انقطع الاتصال — جارٍ إعادة الاتصال…) followsan em dash, i.e. it opens a new clause.
⇒ The 8 were the errors. Pack is now 100:0.
⭐ Should the 8 join #5972's gate? No — and the reason is structural
I read #5972 and its pin (
ellipsis-glyph-3878.test.ts) before answering, andthe answer was measured rather than argued. That gate derives its population
from
en:None of the 8 has
Loading…as itsenvalue — they areLoading grid…,Refreshing…,Loading chart…,Initializing application…,Connecting to data source,Loading configuration,Preparing workspace,Retrying…(measured, table above). So adding them to
LOADING_GROUPwould break thederivation check that is that gate's own anti-vacuity guard — i.e. widening
#5972 requires weakening it. The orthography split is a property of one pack's
spelling, not of a group of shared
enstrings.So this takes the move
de-quote-pairing-3876.test.tsalready made instead, andwhich the #3878 file names as its own precedent: a per-key list becomes a
pack-wide invariant. New file
ar-participle-orthography-6610.test.ts:جاري, noجارى(alef maqsura for theyāʾ), no bare
جارwith the tanwīn dropped, anywhere inar. A ninth valuefails by key name with no one editing the file, which is the half that
lasts; the eight-value edit alone would have left the ninth to be written
tomorrow.
probes inside the test: it must catch all three retired spellings and a
leading و, and must not fire on
التجارية/التجاري(the substring trap anASCII word-boundary regex walks into), on accusative
جاريًا, or on definiteالجارية.skeleton()is asserted to actually strip. Without this the emptyoffender list would prove nothing.
grid.refreshing===list.refreshingminimal pair, so the evidence for the direction is pinned asevidence and goes red if either side drifts back.
important half. It is what notices a later "normalise the ar pack" sweep
flattening a correct distinction into a real grammatical error, which is
strictly worse than the inconsistency this card removed.
ellipsis-glyph-3878.test.tschanges only in itsarnote: its present-tense"the other 8 are a wider normalization filed separately" is now false, so it
records what happened and why widening it was not available. No assertion in
that file is touched, weakened or added to.
Gate verdicts — every one quoted from its own printed line
All on the final commit
161494d4with a clean tree. Heavy work ran throughscripts/pm/os-verify-lock.sh, whose verdict certifies the whole&&chain;exit codes were captured by redirect-then-capture, never after a pipe.
Union run:
VERDICT command-exit 0 · held the lock 62s (1m02s) · waited 268s (4m28s)vitest run packages/i18n/Test Files 58 passed (58)/Tests 927 passed (927)@object-ui/i18n type-checktsc --noEmit && tsc -p tsconfig.test.json, no outputcheck:control-bytesOK (scanned 5519 tracked text file(s); skipped 85 binary)check:i18n-keysEvery in-scope call-site key resolves against the en pack (2831 keys) …check:i18n-driftNo en value changed in this range.check-changeset-presence3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)check-changeset-no-majorNo changeset declares a major bump.check-changeset-fixedAll workspace packages are in the changeset fixed group.check-changeset-overwriteNo pre-existing changeset was modified or deleted.check-lint-coveragelint coverage: 46/46 packages linted, 0 with outstanding errors (0 total).check-vi-mock-specifiersOK (3890 tracked source file(s), 2187 test-named; …)check-shell-escape-residueOK (4/4 root(s) resolved … 0 occurrence(s) outside a fence)check:i18n-dead-keysran but self-declaresThis is a REPORT, not a gate, soit is not counted as a gate result.
check:control-bytesis quoted above and a hand scan backs it, since thisdiff is a file full of non-ASCII:
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over all four changed filesreturned exit 1 (no match).
Not measured, and said so rather than skipped: the two
typecheckinvocationsexcludenothing relevant —tsc -p tsconfig.test.json --listFileslistslocales/ar.ts,ar-participle-orthography-6610.test.tsandellipsis-glyph-3878.test.tsin the program (lines 111/115/419 of 642), so thegreen really does cover the new file.
Lint is a declared narrowing, with all three pieces of evidence:
eslint .insidepackages/i18n, the only package touched; population readfrom eslint's own selection via
--format json= 84 files, 0 errors, 34pre-existing warnings, with all three edited/new source files present at 0/0;
invariance for untouched files =
eslint.config.jsconfigures no type-awarelinting (no
parserOptions.project, noprojectService— grepped, zerorows), so a change confined to
packages/i18ncannot move the verdict on anyfile it does not itself contain. The repo-wide farm is CI's run.
Ablation — 3 legs, each predicted before it ran, from the committed tree
Run under the lock from a committed tree, with
trap restore EXIT INT TERMusing absolute paths resolved fromgit rev-parse --show-toplevel. Each mutation was proven on disk by countingthe injected text and the removed text at the anchor (not by a bare
git diff --stat— the fix itself is an equal-length substitution, so the file'sbyte count never moved and a size check would have proven nothing). Each restore
was proven by an empty
git diff HEAD, and the tree was verified clean at the end.No rebuild was needed and none could have masked a result: the pin imports
../locales/index— a relative source import, not the packageexportsfield — and
packages/i18nhas novitest.config.*of its own, so nothingresolves through
dist/. Leg A proves this empirically: it mutates onlyar.ts, nothing is built, and the test goes red.console.loadingSteps.connectingto the yāʾ spelling.Predicted red naming the key; observed RED, the offender assertion firing
with
1 value(s) still use a retired spellingand the message that tells theauthor what to write, plus the converged-census pin naming
ar console.loadingSteps.connecting moved.console.ai.connectionStalled(جاريًا, where the yāʾis required) to
جارٍ. Predicted red on the yāʾ-is-correct pin only, withthe pack-wide rule staying green, because
جارٍis not an offending form andthe sweep structurally cannot see this defect. Observed exactly that:
1 failed | 3 passed,ar console.ai.connectionStalled lost "جاريًا" — khabar of لا يزال …. That asymmetry is the whole reason the protective pin exists,and it is now demonstrated rather than asserted.
skeleton()made a no-op). Predicted redin the controls block first; observed RED there
(
expected 'جارٍ' to be 'جار') before the pack-wide rule. A matcher that stopsmatching fails its own controls instead of reporting a clean pack.
Leg A the non-vacuity floor was
toBeGreaterThanOrEqual(100)— today's exactcount — so reverting one value tripped it at 99 and the failure a reader saw was
no جارٍ found at allinstead of the offender list that names the key. Anexact-today floor is a ratchet pretending to be a proof of life. Commit
8636f62aslackens it to 80 with the reasoning recorded in the file, and Leg Awas re-run: it now fails on the offender assertion, as it should.
Fences
locales/ar.ts, the new pin, thearnote inellipsis-glyph-3878.test.ts, and the changeset.en.tsis not in the diff at all,and
check:i18n-driftindependently printsNo en value changed in this range.The all-locales parity gate did not force anything: no key set andno placeholder shape moved, so nothing here reaches the other packs.
and still green.
skip-changesetnot applied: a changeset is genuinely owed here(
check-changeset-presencesays so), and in this repo that label is a phantomthat nothing reads, so applying it would only mint a false status.
Examined and deliberately NOT folded in
feminine maṣdar (
إعادة,إضافة,تهيئة,الموافقة,المعالجة); strictagreement would want
جارية. The impersonal frozenجارٍis standard MSA UIregister, and — load-bearing — the pack applied it uniformly on both sides
of this split (7 of the 92, 2 of the 8), so it was never a distinguishing
factor here and it is not a same-screen inconsistency. Ruling it needs an
Arabic desk, so it is recorded in the pin's header as explicitly out of the
file's green, not swept.
chart.loadinghas no consumer. Grepped for the dotted key, for thestrings.xobject-access form that hidesconsole.*from key greps, and fordynamic
t(...)template construction. It is already a standing[needs-review]row incheck:i18n-dead-keys, whose only textual referencesare now this pin and
ellipsis-glyph-3878.test.ts, and that report says everyhit wants a sampled human check before deletion (objectui#4658). Filing a card
would duplicate an existing tracked line, so it is noted next to its pin row
instead, with what to delete if it is ever retired.
Generated by Claude Code