- DESIGN §21 intro: §21.25 now credits PR #2, #7, #10 and #14; the closing additions are mapped (issues #1 / #8 gaps
§21.26, issue #5 / #8 item 5 client fixes §21.27, the draft's match info §21.28, the six 重装 skills' deliberate
trigger deviation §21.29), the merge order names the four closing branches (their three "§21.26" subsections
renumbered §21.26-§21.28 in merge order) and GitHub's master, and the normative lines they rewrote are listed.
- DESIGN §10: a strategy built around a switched-off bond carries the 本局禁用 mark in the strategy draft (§21.26).
- CHANGELOG 0.1.1 intro names the GitHub issues and pull requests handled.
- docs-consistency: §21.1-§21.29 present and numbered consecutively; the intro's new mappings.
test/sim/robustness.test.js "performance: heavy 2-player boss field" failed on GitHub's windows runners (0.51-0.58 ms
per tick against the 0.5 ms bar) on PR #10, PR #12, PR #14 and master's own push. The bar stays 0.5 ms on a development
machine and is 1.0 ms when process.env.CI is set (GitHub sets it); the measured time is the best of three runs of the
same battle after two warm-up battles, each run still checking the peak, the 18 operators and zero errors. Documented
in the test header, DESIGN §11 and the CHANGELOG's 工具 section.
css/screens/loadout.css: `.lo > * { position: relative }` (one class, a later rule) overrode `.lo__bg { position:
absolute }`, so the mint glow / grid layer was a 0-px flex item and never rendered. `.lo > :where(:not(.lo__bg))`
keeps the one-class specificity for every other layer and never matches the background.
Checked in headless Chrome at 1920x1080 and 844x390 (touch): the layer now covers the overlay (0 px tall before),
every other box of the screen is unchanged, no console errors. Tests: test/ui/loadout.test.js (the cascade; fails on
the old rule), opt-in test/ui/loadout.e2e.test.js (the layer's box and stacking at both sizes). DESIGN §21.25 credits
PR #14 and PR #10 (crossOrigin on the two new Image() loads); CHANGELOG 0.1.1 lines for both.
The owner's decision (2026-10-03, after community feedback): 深巡 S2 行动能力剥夺, 雷蛇 S2 反击电弧, 号角 S2 暴风号令
and S3 终极防线, 灰毫 S1 攻击力强化·γ型 and S2 专注轰击 take the basic strategy (DEFAULT) instead of the 下半 TANK class
row's TAKE_DAMAGE. Every other MANUAL 重装 skill, 深巡 S1 included, still waits for a hit.
- tools/build-data.mjs TRIGGER_DEVIATIONS: a small table keyed by the normal chess id and the skill id (the elite
follows through baseId), never by the skill id alone - 灰毫 S1 is the generic skcom_atk_up[3]. resolveTrigger applies
it last; rawRule keeps the official TAKE_DAMAGE; validateAll fails the build when an entry no longer meets a
TAKE_DAMAGE row. data/chess.json rebuilt with --offline: exactly the 12 records' rule changes.
- PR #12's kit lines (trigger 'DEFAULT' on 深巡 / 雷蛇 S2) stay and agree with the data; their comments and tests now
give this reason instead of the community summary.
- Tests: test/sim/feedback1-tank-triggers.test.js (the data, kit = data, a real battle on 战场#01(下半) in which each of
the six casts with an enemy in range before any hit and each of the other 46 MANUAL 重装 records casts on the first
hit); data.test.js trigger expectations; the 灰毫 / 号角 kit tests follow; docs-consistency.
- Docs: DESIGN §21.29 (new), §5.6, §19.2, §20.2, §21.20 (settled row), §21.23; DATA, SIM, PLAYING, CHANGELOG 0.1.1;
research 03 §1.4 drops the arknights.wiki.gg "offensive / defensive" summary and records the activity_table history
(上半 had no TANK row, 下半 added it) and this deviation; research 00-INDEX.
Conflicts resolved keeping both sides:
- bandDraft.js header: the 本局禁用 mark of a strategy tied to a switched-off bond, then the 本局信息 dialog; the code
merged cleanly (the card's 本局禁用 tag and the detail note sit beside the dialog's state and button).
- draft.css: the 本局禁用 tag / note rules, then the 本局信息 entry and dialog block (its header cites DESIGN §21.28).
- CHANGELOG 0.1.1 界面: the gaps and issue #5 / #8 lines, then the dialog line.
- PLAYING §6: the disabled-bond line says where to look again (draft dialog, in-game 🔍); the 变形同构体 line keeps its
pairing explanation.
- DESIGN: the branch's "§21.26 Match info in the strategy draft" becomes §21.28; its two §10 references follow.
Conflicts resolved keeping both sides:
- CHANGELOG 0.1.1 界面: the three gaps lines, then the issue #5 and #8 lines.
- DESIGN: the branch's "§21.26 Client fixes for GitHub issues #5 and #8" follows the gaps' §21.26 as §21.27; its
references in §9 (setCamera `shop`, the model fallback), §17.1 (the quiet budget) and §19.8 (the collapsed shop)
now point at §21.27.
Conflicts resolved keeping both sides:
- effectsMeta.js header: the QA residual's "every [holder, item] pair, taken before the first item runs" and "an item
moved during it runs at most once", with the cell branch's wording of what 突变细胞 does mid-walk.
- DESIGN §6.6: the band pick that skips a strategy tied to a switched-off bond and the deployment of the operator a
transformation gains / the bench shed that spares it.
- DESIGN §21.25: PR #2's bench rule credited (the cell branch) plus the QA residual's snapshot-timing sentence.
- PLAYING: the new 突变细胞 sentence with the residual's hammer sentence (revives, borrowed hammers, the lend window).
- docs-consistency: both new tests (batch 6 QA residuals; 突变细胞 after the WA merge).
The hammer lock per deployment for borrowers and in-place revives (both [ASSUMED] where no source decides), 卢西恩 / 锏
casting for an airborne 蒂比, rule 3 for a summon that is gone, the dispatcher snapshot taken before the first item;
PLAYING and CHANGELOG no longer say every debuff misses an airborne 蒂比 (ground-enemy auras and counters still reach
her); research 04's hammer line says once per deployment. docs-consistency pins it.
卢西恩's 【aoe】 and 锏's CircleAttack counted every ally in their radius, so an airborne 蒂比 alone in range set them off
and the blast skipped her. They count only allies a ground enemy does not evade (evadesGround).
A summon leaves its home free only once it has expired or been killed, and _layBody skipped removed pieces, so a body
on the home of 浊心斯卡蒂's expired 海嗣 stayed there and kept the 海嗣 from coming back. Every board piece's home counts
now. _checkRedeploys tests the DP before the tile scans, so an operator waiting for DP no longer scans every ally.
Step 5 read each holder's items when the walk reached that holder, so an item equipped meanwhile onto a holder not yet
walked ran in the same dispatch and an item moved to a later holder ran twice (latent: no shipped item does either).
Every [holder, item] pair is now taken before the first item runs, as the header and META already said.
The lock and its re-arm hook lived in the carrier's hammer grants, so a hammer lent by 萨尔贡 × 娜仁图亚 came back spent
in the borrower's next deployment once the lend had run out while it was down, and a window started through the lend
ended with it. deploymentOf marks the deployment whose lock is spent; one battle-level hook holds every running window
(holdsUndying, also what 信仰搅拌机 S2 steps aside for), so a window outlasts the lend. M3茧甲 and 埃芒加德 revive in place
for PRTS's 0-time / 0-cost redeploy and now open a new deployment (revivedInPlace), like 阿戈尔 5's real redeploy.
At 640×360 the mock's first shop card completes a merge; its detail opens in
the left slot and moves to the right one 20-40 ms later because the elite's
lit board tile lies under the left slot (screens/game.js dSide, DESIGN
§20.11). The check caught the left card only sometimes and then measured the
corner buttons against the right one. It now taps a card without a merge and
asserts the card stays left.
A reload (a phone browser or Chrome's Memory Saver discarding the background tab) made the asset store download
/data/assets.json a second time; createFieldView waited at most 4 s for it, every view looked its model and avatar up
once, and a failed download kept an empty manifest for the page. Now the field host seeds the store with the game
data's copies (seedAssets); without one, ready() retries like data.js, never keeps a failure and tries again with a
bounded backoff, and onChange makes every view re-resolve (UnitView.retryAssets, ItemView.setIcon). A failed or
timed-out Spine load is retried by its view (SPINE_RETRY_MS, acquire { retry }) and at once when the tab is shown.
Battle mode holds the Spine cache (spine.hold()), so a battle that began in a hidden tab keeps its models; the idle
budget still applies and the quiet budget still frees everything in the lobby, room and result.
While the own prep board is shown and the shop bar is folded, the game asks for the prep camera with shop: false
(left_prepare_camera_param / the boss prepare params) and the view keeps the bench above the folded shop's HUD band:
the higher of the folded tab and the corner buttons' hit areas (hudBands(kind, size, { shop: false }), cornerBand).
Unfolding returns to the shop camera. Never over the pen, a teammate's board or a battle; deferred while a piece is
dragged or its direction is chosen (gameLogic prepCameraFor / foldCamera). Below 768 px of width the corner stays on
one row while the bar is folded. Tile px at row 10: 1920x1080 109.8 -> 130.7, 844x390 35.9 -> 44.3,
756x366 31.4 -> 40.1, every bench pad fully pressable.
One component, public/js/ui/matchInfo.js: matchInfoModel (the drawn set D and
the mode's inactive bonds via disabledBondSets, the briefing's bond order,
banned operators by tier, bannedPerBond) and the briefing's bond rows, legend
and banned-operator grid. The briefing renders it; the band draft opens it
read-only in a dialog (查看禁用盟约与干员 under the order list; 关闭, a tap
outside or Esc close it; its footer repeats the turn and the countdown; a turn
change closes it, the end of the draft unmounts it); the in-game 本局信息 tab
reads the same model, so its banned operators are listed by tier too. In the
dialog every size has a px floor, so phones keep readable text and a
scrollable body.
Tests: test/ui/match-info.test.js; opt-in test/ui/match-info.e2e.test.js
(SP_E2E=1: solo 标准 on desktop, co-op 绝境 with a desktop and a phone).
A band whose bondIds meet the mode's inactive bonds (gameLogic bandOffBonds,
the same field and rule as the bot) gets a 本局禁用 tag on its card and, in
the detail pane, "本局禁用【拉特兰】盟约,此策略效果可能无法发挥" with the bond
struck through. It stays selectable. In 标准 that is 潘格尼尼, 克莱门莎 and
玛恩纳; no band is marked in the other modes. A test pins the client mark to
the server's exclusion in every mode; the headless check covers the draft
at 1920x1080 and 844x390. DESIGN §21.26, META and the CHANGELOG say so.
The band -> bond derivation moves out of GameData into shared/bandBonds.js,
which tools/build-data.mjs runs per band to write bands.json bondIds
(regenerated with --offline; 9 bands are tied, the build checks the ids).
GameData.bandBondIds reads the field, so the server and the client share
one source. DATA.md documents the field; the test checks the helper on
synthetic bands and that the data matches it.
With the bench rule the gained operator starts the next prep on the bench while its carrier's deployment
is free. The buy loop's pre-emptive bench shed sells the weakest bench single by piece value while the
bench is crowded, before the placement step runs: in 20 solo 绝境 matches on 昆图斯 it sold 44 of 222
gained operators that way.
- bot.js: botPrepEndSteps remembers the chess owned when the prep ends (rememberOwned); the shed's
keepFresh now also spares a piece gained since then (a transformation's operator, battle-result /
round-start grants), so the lineup step decides about it. No memory yet (a first prep, a seat just
put under AI 托管) changes nothing.
- botbench, decisions only: 昆图斯 (seeds 201-220) 绝境 7 -> 11 / 20 wins with the fix (8 on the WA
build), 险境 16 -> 17 / 20 (15); the bots' own strategies unchanged within noise (solo 绝境 8 / 12 both,
solo 险境 19 / 24 both, co-op 绝境 4 AI 9 -> 8 / 36).
- Test: a real solo 绝境 昆图斯 bot match (seed 9 sold its R7 operator in the R8 prep before the fix):
no gained operator shed in its first prep, none waiting on the bench beside a free deployment.
- DESIGN §21.1 / §21.6 / §6.6, META and the CHANGELOG line say so.
With the bots' new band picks the full-match suite's coop/FUNNY/107
reached a 6-谢拉格 freeze board at R12 whose honest +112 谢拉格 layers passed
the flat 60 + 4*round = 108, so the server rejected the client and
re-simulated (SP_VERIFY=all agrees with the client on all 57 battles).
validateClientResult now adds, per bond, what the player's IN_BATTLE layer
traits can add to it: each trait of its units and each one their ADD_BOND
traits hand out (once per operator), up to the per-battle cap the sim
applies; a trait without a cap, or a 魔王, leaves the bond bounded only by
the room under 999. Other bonds keep the flat bound. DESIGN §14 / §20.12 /
§21.26, META and the CHANGELOG say so; tests pin the R12 board and the
capped, handed-out and 魔王 cases.
- DESIGN §21.1 states the corrected rule with its evidence: bilibili BV1vzyVBuEN9 (上半, about 8:24) and
BV1Qkw1zMEoR (下半, about 7:25) show the carrier's tile empty at the next prep, one more deployment left
and the new operator on the bench; the PRTS 备注 is a destroy followed by a gain; PRTS 帮助 sends what a
player gains to the 手牌区; the closed PR #2 said the same (its merge path not adopted). The WA
keep-the-tile rule and the carrier-tile merge exception are withdrawn; the bench carrier and the
hand-and-temp-full case stay [ASSUMED].
- §20.11 / §20.9 no longer count a transformed carrier's tile; §21.20 lists the rule as official;
§21.25 credits PR #2's bench rule; §6.2 and §6.6 follow; the §21 intro maps it.
- META (bot, ctx.transform, built-ins, merge, notes), PLAYING, DATA (items.json note), research 04
(addendum 2, implFormula, open question 6) and research 01 row 7 follow.
- One CHANGELOG 0.1.1 line (PR #2 指出).
- docs-consistency pins the docs against the code (no fromKey / returnItems left, the gain through
acquireChess).
Official gameplay footage (bilibili BV1vzyVBuEN9 at about 8:24, BV1Qkw1zMEoR at about 7:25) shows the
next prep with the carrier's tile empty, one more deployment left, and the returned equipment plus the
new tier+1 operator on the bench, deployed by hand afterwards. That is the PRTS 备注 read as written
("生效时,原干员销毁,获得一名高一阶的随机初始干员"): a destroy followed by a gain. The closed PR #2 made
the same claim from a playtest.
- PlayerState.transformChess: the carrier is destroyed wherever it stands (board tile freed, summons
removed, copies back to the pool); its equipment, the cell included, returns to the hand first
(overflow temp, auto-merge); then the new operator is gained through acquireChess like any gained
operator (hand, overflow temp, the no-room rule of every gain; no summon card until it is deployed).
The returnItems option is gone (the cell's built-in was its only caller).
- A merge the gain completes merges like any gained copy: the elite takes a consumed deployed copy's
tile, else the hand. _mergeChess loses fromKey / fromDir, so the destroyed carrier's tile never
counts (PR #2 had kept that path; not adopted); audit.js drops its exception for it.
- builtinMeta, ctx.transform, items/meta.js and bot.js comments follow. Bots and AI 托管 deploy the
gained operator in their normal lineup step (no bot change needed; a real co-op round pins it).
- ITEM_RULES note and implFormula for the item card; data/items.json rebuilt with build-data --offline.
- Tests: facing, merge, playtest6-elite-to-board and items no longer pin the kept tile; feedback1-meta
covers a deployed and a bench carrier, hand full -> temp, hand and temp full, a merge with and
without a deployed copy (never the carrier's tile), 商业包装方案's count on the returned item, and bots /
AI 托管 redeploying; feedback1-cell checks the new note.
test/ui/feedback1-gaps.test.js: the 14-bond list from the data (checked
against the official talent when the cache is there), 本局禁用 in 标准, the
wearer highlight, the cards, the 调和 row in the own and a teammate's
popup. test/match/feedback1-gaps.test.js: the harmony mark in the states
and views, bandBondIds, botPickBand over seeds 1-200 solo and co-op in
标准 and 绝境, the fallback, the docs. test/ui/feedback1-gaps.e2e.test.js
(SP_E2E=1): the cards and the popup in headless Chrome at 1920x1080,
844x390 and 756x366.
DESIGN maps F1-F5 in the §21 intro, adds the hammer-per-deployment row (user 2026-10-03) to
§21.20 with the batch's official rules and [ASSUMED] items, and rewrites the normative lines:
§3 fenced tiles, §5.3 liftoff, §5.4 fatal / ignoreSelect / redeploy, §5.5 bodies, blocking and
enemy selection, §6.4 onBuy and the item snapshot, §8.2 down row/col, §18.3, §19.7. CHANGELOG
0.1.1, SIM, DATA and PLAYING follow; docs-consistency checks them against the code.
A rebuilt manifest leaves out every entry whose files are missing on that machine, so a run
with failed downloads silently dropped entries from the tracked file (PR #7 carried one 42
audio entries short; all 42 still resolve upstream). The run now keeps the current manifest,
prints the entries it would drop (also in the report) and exits 1. The tool runs main only as
a script so the guard and parseArgs can be tested; ASSETS.md documents the flag.
Step 5 iterated holder.items live while handlers move and destroy pieces: normal 博士投影
splices itself out (the next item on that holder was skipped) and 突变细胞 transforms its
holder (the next item ran with a holder that was gone). It now walks a copy and runs an item
only while it is still equipped on its still-owned holder; the rule is in the header and
META.md. Tests use a synthetic spy handler after the 突变细胞 and after 博士投影.
The carrier's own non-initial deploy (the redeploy after a knock-out, a 突袭 retreat +
redeploy) re-arms the lock and ends a window still running. The per-battle test is flipped
and a retreat + redeploy case added.
Conflicts resolved keeping both sides:
- buffs.js FLAG_KEYS: liftoff beside the integration's selfBound.
- Battle.js: targeting import union (extendedGrid + evadesGround); _blockerFor keeps the
fenced-tile gate (WU) and adds liftoff; applyStatus keeps the 无敌 + 无法选中 refusal and
adds the 对地规避 refusal.
- enemies.js: header DOT entry from WT with the integration's INVISIBLE entry; import union;
enemy_1273_stmgun_2 keeps the integration's rewrite (it filters through canTargetAlly,
which now includes liftoff).
- tier2.js 蒂比 comment: the integration's 受到伤害前触发 text plus the 起飞 line.
- tier5.js 隐德来希 血镰: liftoff flag with the integration's foesInRadius.
- SIM.md: blocking keeps the fenced-tile passage and adds air-only blocking while airborne;
the 污染秽蚀 / 燃烧区域 sentence goes before the chimera aura; statuses keep both refusals.
Both 哨戒铁卫 S2s (深巡 行动能力剥夺, 雷蛇 反击电弧) are OFFENSIVE skills but waited for a hit: the official
技能策略 row `TANK | | | 0 | TAKE_DAMAGE` is documented for skillIndex 0, and reading it as a wildcard for
every index handed TAKE_DAMAGE to these two skillIndex-1 skills (issue #4).
The mode's rule (docs/research/03-operators.md §1.4, quoting the in-game help) is "offensive skills activate
when an enemy is in their skill range; defensive skills activate when the unit is receiving damage", so both
take the basic strategy instead.
- kits/tier1.js: `trigger: 'DEFAULT'` on 深巡's default S2 and on 雷蛇's. Only the rule changes — spCost /
initSp / spType still come from data. The defensive S1s (深巡 侵袭破坏应对, 雷蛇 充能防御) keep theirs.
- tests: the two 雷蛇 tests that pinned the hit-gated cast now assert the basic strategy, and their enemy
stands two tiles away so it never touches her; 深巡's test drops its forced dealDamage hit; a new test covers
all four records (normal + elite of both).
node --test: 2888 tests, 2871 pass, 0 fail, 17 skipped.
The buy loop's pre-emptive shed sold the single it had just bought back for 1 (the buy picks
by lineup gain, the shed by piece value). Same-prep buy then sell in co-op 绝境 seeds 21-26:
29 -> 3. Seeds 1-40: solo 绝境 22 -> 24 wins, co-op 9 -> 10 on the 22-match bounty lists;
decision time unchanged.
A catch-up frame or a hidden-tab step drains its events every EV_SLICE (15) ticks and each
batch is stamped with that game time; the held backlog is emitted batched by the time it was
drained at. The render engine then sees a late form fx as late and skips a change clip that
would already have ended (a 转译基底·α no longer replays A_Die_C 16 s after its change).
- Battle.applyStatus: a unit both invulnerable and untargetable takes no status from the
other side (PRTS 无敌 "无法被不同阵营选中"), so the status carried by the hit that knocks an
enemy out (妮芙 S2's fear, a 叙拉古 proc) no longer lands after its 重生 cleanse.
- Flag selfBound (自缚: 守墓石像's 转换模式, the 自缚 leaders, the 胄 parts' anchor): 余 S2
never teleports such a unit (PRTS 余 S2 备注 "持有自缚的单位不视为可达目标").
- 信仰搅拌机 S2: with fewer than ammo_cost bullets the lethal hit is still blocked, every
bullet goes and the skill ends; it steps aside while 坚固维式重锤's 不死 window holds her
(PRTS 备注), replacing the [ASSUMED] no-guard rule.
Merges the 7 WB commits after the first WB merge (d1f8a49..2cb84bd): R3 one of 10 fixed
sets (9 seen), R9 one of 6 boss groups picked by the matches they came in, R11 one of the
7 seen lists of 7; R11 families 14 / 4 / 4; the 机密商店 and the 战术决策 can offer the
same card twice (R11 shop: two VI, at least one V and one 盟约之币). data/choices.json
rebuilt with tools/build-data.mjs --offline (identical to the branch's). The tactic bot
test uses a real seat (the merged bot scores tactic cards on the player's bonds).
DESIGN §21.2 / §7 / §21.20 and CHANGELOG describe the 22-match model.
The user: "战术决策也按官方改成可以重复吧". The 4 official 战术决策 (R11 of
matches 7, 9, 18 and 20) show six cards each; match 7 offers 补给 twice.
- Every 战术决策 card is drawn on its own (with replacement), so the same
card can come twice. choices.js tacticDraftCards / tacticCard.
- R11 (绝境 / 终极, the round of the screenshots; choices.json tacticDraft,
build-data TACTIC_DRAFT): only the ally cards, weighted 1 + the official
cards each showed on. All 24 official cards are ally cards (no 排斥 /
责罚 / 裁决, no terrain card: about 0.04 % for the previous draw) and
列装 / 财富 / 补给 / 整备 / 升华 made 12 of them (uniform: about 4.6).
Other rounds (标准 / 险境, no screenshot) keep every card, uniform, with
replacement too. The weights and the R11 terrain exclusion are assumed.
- The header is the official "进行协同调整,做好迎战准备。".
- Identical cards are separate cards: own index, own object; a pick
applies its card once and leaves the twin pickable; two picks of a team
card stack. Match / bot / overlay already go by index.
- Tests: official drafts vs data, generated R11 / solo / earlier rounds,
a seeded draft with 补给 twice, co-op and solo E2E picks of twins, the
bot, the overlay, and a headless-Chrome render (game-mock variant=tactic
is now the official match 7 draft). Tests that drive given tactic cards
lay them out explicitly. The 奥术 Final Assault test takes the first of
a few seeds whose bots pair two 奥术 players (the draws moved seed 12).