Батч 3, шаг 3. Сначала измерено, а не придумано: прогнаны 130 файлов
gamemodes/sandbox, извлечены 182 различных вызова API с частотами.
Топ по частоте: hook.Run (63), math.Clamp (61), game.SinglePlayer (36),
math.Rand (27), render.AddBeam (21). Первые четыре — чисто Lua-слой,
сделаны здесь; render.* — отдельная большая работа.
hook.Run не синоним hook.Call: он останавливается на первом не-nil. На этом
построены все проверки Sandbox, подмена Run на Call ломала бы их молча.
Найдено три дефекта, все — измерением:
1. Ключи хуков — строки (идентификаторы скриптов), а не числа. Отбор только
целочисленных ключей давал пустой список: хуки не выполнялись вообще,
hook.Run возвращал nil.
2. Vec<Value> реализует IntoLua как таблицу, поэтому Function::call передавал
хуку ОДИН аргумент вместо трёх — молча, без ошибки. Проверено:
select('#', ...) внутри хука давал 1 при трёх переданных. То же с одиночным
числом. Лечится Variadic; отдельный тест фиксирует именно эту ошибку.
3. math.Rand определён на Lua, а не на Rust: он зовёт math.random того же
состояния и передаёт аргументы нативно.
file.* — с песочницей на garrysmod/: выход за корень это отказ, а не
предупреждение, абсолютные пути не даны, чтение ограничено 8 МБ. На живом
клиенте file.Read('../../../../etc/passwd') вернул nil.
Совпадения с GMod зафиксированы тестами: math.Round(-2.5) = -3,
math.Rand(x) даёт целое в [1, x], AngleDifference(10, 370) = 0,
Remap на вырожденном диапазоне даёт out_min, а не NaN.
Тестов 38 в glua (было 24), 23 набора по воркспейсу, clippy чист.