Решили: правило детерминизма из code-standards §8 переписано с двух полос на три ступени,
и критерий сменился с «кто это считает» на «кто сверяет результат». Плюс требование к запеканию
ослаблено с межмашинной побайтовости до воспроизводимости на своей машине.
Почему: двухчастная версия (Three Lanes,
написана часом раньше) сказала: показ-рандому «сходиться не с чем». Через час при сборке
Lib/Procedural.hlsl выяснилось, что в SH_Vfx_HitForm стоит прямо противоположное и стоит
обоснованно: неровность краёв формы удара обязана совпасть у всех клиентов коопа, поэтому сид туда
приходит из IRngService, а шума по времени там нет и быть не может. То есть между «строгим сим-рандомом»
и «свободным показом» живёт третья ступень: число не читает симуляция, но картинку сверяют глазами
двое — и на ней ошибиться легче всего в обе стороны. Тянуть её в IRngService целиком избыточно,
считать свободной — значит показать двум игрокам разные удары в одном бою.
Отдельно ослаблено требование к запеканию. «Побайтово тот же файл на любой машине» я записала по инерции от сим-рандома, а Макс спросил, какие это ситуации, — и их не нашлось: текстуры печёт один человек, CI их не трогает, игрок получает готовый PNG. Настоящая причина держать воспроизводимость другая и меньшая: PNG жмётся целиком, поэтому любой сдвиг переписывает файл полностью и даёт диф там, где визуально ничего не изменилось. Побочный эффект: с отменой требования отпало и C#/HLSL-зеркало с тестом золотых значений, которое я собиралась писать ради него.
Сказано: «А зачем нам прямо чтобы между машинами было 1 в 1? Про какие ситуации речь, для чего?
Разве будут большие отличия?» (02.08.2026, сессия f76789b3).
Грабли: правило прожило час и соврало на первом же файле, который под него попал. Причина не в
спешке, а в порядке работы: я написала его до того, как прочла код потребителей, — инвентарь
собирался по названиям файлов и по архиву диалогов, а не по телу шейдеров. Обоснование третьей
ступени всё это время лежало комментарием в SH_Vfx_HitForm и было бы прочитано на пять минут раньше,
если бы сборка библиотеки шла перед формулировкой канона, а не после.
Второе: реальное дублирование оказалось не тем, которое я анонсировала. Три «разных рандома»
(XorShiftRng, sin-хеш осколков, шум запекателя) — три разные задачи, сводить их незачем; зато
матрица Байера и BayerThreshold стояли дословным copy-paste в MapFogCommon и
MapTransitionCommon, и их я не заметила, пока не грепнула по телу файлов.
Третье, мелкое и злое: массовое переименование вызовов через sed переименовало заодно и само
определение функции в SH_Sprite_Shatter, создав конфликт с библиотечным. Ловится только чтением
диффа — компилятор шейдеров при этом молчал бы про «уже определено» ровно до переимпорта.
Владелец правды: Reference - Code Standards §8 (таблица трёх
ступеней) и Assets/_Project/Art/Shaders/Lib/Procedural.hlsl — в самих функциях проставлено, для
какой ступени каждая годится. Прецеденты: SH_Vfx_HitForm (вторая ступень), SH_Sprite_Shatter
(третья). Тестом ступени не закрыты и закрыты быть не могут — шейдерный код у нас вне тестового
контура; держится обзором диффа и комментарием в точке использования.