-
Nikitos создал
Разобран весь §9 — восемь пунктов. ИСПРАВЛЕНО: * installControls — мёртвый код (живой def('controls') в ядре): функция и импорт удалены; * Math.random() в rig таймлайна (дыхание и фаза героев) — заменён на fxRandom: он сеется движком, поэтому воспроизводимость при --seed/--fixed-dt и реплеи ($.replay) больше не ломаются; * ui.on съедал слот обработчика ДО проверки успеха: неудачная подписка выжигала слот вместе с JS-функцией, и на 256-й такой попытке движок падал с InternalError, хотя обработчиков было меньше лимита. Теперь слот занимается только после успешной подписки, а функция освобождается при отказе; * visit_mark в BSP: поле и выделение удалены — память выделялась на каждый рост дерева и не использовалась; * комментарий «engine.width замирает при старте» в widgets.js исправлен (все три источника обновляются при resize). СТРАЖ НАШЁЛ БОЛЬШЕ, ЧЕМ АУДИТ: добавленная проверка «ни один модуль API не зовёт Math.random» сразу поймала ещё два места, которых в §9 не было: * steps.js — выбор файла шага и разброс высоты тона шли через Math.random (четыре вызова), теперь fxRandom; * soundbank.js — выбор варианта и разброс громкости/тона (три вызова). Здесь важна тонкость: чистые помощники (pickBankFile/bankVolume/bankPitch) без переданного генератора теперь возвращают ПРЕДСКАЗУЕМЫЙ результат, а не «случайный по умолчанию»: чистая функция обязана быть проверяемой, а разброс игре даёт переданный fxRandom. r2d_physics_is_awake и KEY_NAMES в §9 были помечены мёртвыми ошибочно: первый используется в engine.isAwake/$.world.awake, второй заполняется через engine.keyName (исправлено в прошлых раундах). §9 переписан как таблица «что было → чем закрыто». Проверка: полный набор qjs (28 файлов), агентские тесты, r2d_bsp_test (11), doc_coverage, doc_claims, duplicate_keys (включая нового стража Math.random), быстрый набор — зелёные.8b72592c