Potential becomes a per-player setting (the owner's decision of 2026-10-08: 「调配干员里自己设置吧,默认满潜满加成」;
official: 调度手册 「卫戍协议中干员潜能由自身已持有干员潜能决定」). 0.2.1 baked full potential into the data (§26.14).
- tools/build-data.mjs runs the chess / backups / tokens builders once per potential rank (ctx.potRank, 0–5) and keeps
the full-potential build annotated with what each lower rank changes: `potDown` { rank: { dotted.path: value } } on
chess records, backups.json forms and token variants (stats, statsBase; 望's 棋子 deployLimit / deckStack, 多萝西's
共振装置 count), and chained talent entries (`potMin` / `potBelow`: the candidates by requiredPotentialRank, the
fields a lower rank changes) in talents / talentsBase / modules[].talentChanges / variant talents. A self-check proves
shared/potential.js atRank rebuilds every rank exactly; the unit-form parity runs at every rank.
- shared/potential.js (new): atPotential / atRank, talentAtRank, stripPotential, and the 练度 helpers used next
(cultivateMul from the effects.json CHAR_MAP records aceffect_char_1…4, cultivationOf, cultivatedStats).
- composeTalents / composeUnitRecord return potential-resolved lists (no chains): a composed record is built at one
potential (its form resolved first).
- JSON compare: the new chess / backups / tokens minus the annotations equal the old files byte for byte; every other
data file identical; data/i18n/* rebuilt (the chained talent texts translated at the old rates: en 95.4 %, ja 95.2 %,
ko 95.2 %, zh-TW 90 %). Data 5.21 → 5.51 MB.
- Docs: DATA.md §2.3 (new), §2, §7, §14, §16, §18; research/03-operators.md; kits/README.md.
- Tests: test/potential.test.js (new, 7): every chess and 自选 form at every potential = the raw keyframes plus the
potential steps up to it, every talent = the last candidate with requiredPotentialRank ≤ the rank, 刺玫 at each
potential, summons at the owner's potential (Mon3tr 3 s / 1200, 望's 棋子 6 / 7, “小自在” 15), the 练度 table =
cultivateEffectList; data.test.js compares the composed talents without annotations.
Conflict: server/match/player/basics.js imports (W5G's checkNotOwned + W5I's msg / dn). data/i18n/en.json rebuilt on the merged data (tools/build-i18n.mjs --offline): the 自选 data adds texts of CN-only operators and modules the EN client lacks, so coverage is 97.6 % (skills 95.9, talents 95.1); the coverage floors in test/i18n-data.test.js and docs/I18N.md say so. Golden unchanged; i18n / lobby / match / ui suites 1144/1144 after the rebuild, i18n e2e 1/1.
shared/i18n.js: gettext-style t() / tc() with the Chinese text as msgid (untranslated -> Chinese), {name},
{0} and {n|one|other} params, lists, game-data names (dn / tName), setLang / getLang / onLangChange, and the
server message wire format (msg -> wireMessage -> translateWire). Chinese stays the default, English is a
switch (the owner's decision of 2026-10-05).
tools/build-i18n.mjs (build-data.mjs untouched) walks the zh_CN and EN tables side by side and writes
data/i18n/en.json: the official English of every data/*.json text by record id and field. Blackboard texts
are matched by template (the remake's numbers read back and filled into the English template); stage names
are composed; what the EN client lacks falls back to tools/i18n/fallback-remake.json and fallback-pr70.json
(PR #70 by @YuriRestia). Default EN source ArknightsAssets/ArknightsGamedata (has act2autochess);
Kengxxiao/ArknightsGameData_YoStar is archived (2025-11) and has no 盟约 season (--source yostar).
Coverage: 14 922 / 14 931 texts (99.9 %), 99.3 % official; only 9 CN-only 甄选 operator names stay Chinese.
shared/i18nData.js: the overlay format (index-aligned leaves + a 2-char hash of each Chinese source, so a
stale leaf is never applied). public/js/data.js: setLocale('en') downloads the overlay once; get / lookup /
list return localized copies; getRaw keeps the Chinese file; localeName maps names.