Решили: событие ленты несёт долю тика (TapeEvent.SubTick), PumpTo берёт её вместе с долей кадра показа, а запись держит ленту отсортированной по паре (тик, доля) вставкой, а не слепым Add.

Почему сортировка при ЗАПИСИ, а не разбор при подаче: подача идёт линейным курсором, и событие с долей 0.9, записанное раньше события с долей 0.1 того же тика, задержало бы второе до своей доли — то есть sub-tick точность съела бы сама себя, причём именно в самом частом случае (порядок записи внутри тика — это порядок обхода юнитов, а не порядок моментов). Альтернатива «оставить Add, а при подаче пропускать незрелые и возвращаться к ним» требует признака «отдано» на каждом событии вместо одного курсора: дороже и на каждом кадре, ради случая, который лечится единицами сдвигов при записи (события приходят по возрастанию тика, сдвиг возможен только среди событий последнего тика).

Вставка стабильна намеренно: при равных долях порядок записи сохраняется, поэтому у событий без доли — смерть, наложение эффекта, периодика — поведение осталось прежним. Без этого правка ради точности удара незаметно переставила бы всё остальное.

Сказано: «Давай саб тики, а потом пошли фазу А» (01.08.2026, сессия 9e6eef1b). Само решение делать sub-tick подачу принято им 31.07 отдельным заходом, к коопу не привязанным.

Грабли: доля обнуляется, если момент контакта склампился (телеграф-пол MinWindupTicks или потолок «интервал − 1»): кламп сдвигает момент искусственно, и дробь от сдвинутого числа была бы точностью, которой нет. Второе — PumpTo обязан отдавать прошлые тики целиком, независимо от alpha: доля показываемого тика к ним не относится, и сравнение по паре без этого условия теряло бы события на долгом кадре насовсем.

Владелец правды: Combat/Tape/TapeEvent.cs, Combat/Tape/BattleTape.Record, Combat/Tape/BattleTapeDispatcher.PumpTo; инварианты — тест TapeSubTickTests (сортировка внутри тика, стабильность для событий без доли, прошлые тики целиком, дефолт alpha = 1).