Решили: въездной замах (старт за границей досягаемости, кадр контакта на входе в неё) выдаётся КАЖДОМУ подбегающему мили-юниту, а не только набравшему разбег. Признак въезда — своё поле RuntimeUnit.ChargingIn, отдельное от ChargedSwing. Заряд удара с разбега гаснет при прибытии.

Почему: механизм существовал, но стоял за условием ChargedAttackReady, поэтому работал у меньшинства: остальные добегали, тормозили и начинали замах уже стоя — удар опаздывал на всю длину замаха относительно момента, когда дистанции хватило. Альтернатива «чинить только показ, механику не трогать» отвергнута Максом: она оставила бы расхождение между картинкой и расчётом.

Два поля вместо одного — потому что вопросы разные. ChargingIn отвечает «когда случается удар» (и по нему движение снимает рут с замаха), ChargedSwing — «каким он выходит» (клип рывка, укороченный замах). Если бы рут снимался по ChargedSwing, все неразогнавшиеся въезжали бы зарутованными, то есть замахивались бы в пустоту в двух шагах от цели — ровно тот баг, ради которого рут когда-то и снимали.

Грабли: StopSprint и AbortSprint различались одним полем — переживает ли заряд конец разбега. После решения «прибытие тратит заряд» разница исчезла, и два глагола на одно действие пришлось слить обратно в один: пока их было два, выбор между ними в каждой ветке был молчаливым решением о механике.

Цена изменения — боевая, а не косметическая: мили начинают бить раньше на длину замаха. Заведено на замер как BAL-019, потому что коридоры DPS считались при старом тайминге.

Владелец правды: AutoAttackSystem.ChargesIntoReach / EnterWindup, RuntimeUnit.ChargingIn, MovementSystem (рут замаха), тесты ChargeAttackTestsPlainRunner_AlsoStartsItsWindupOutsideReach и StandingUnit_StaysRooted.