Вторник, восемь сорок. На столе лежит вчерашняя распечатка с двумя колонками чисел — третья строка сверху перечёркнута синей ручкой, ручка так и осталась лежать на листе. Перечёркнуто вот что: вчера я написала, что тридцать первого октября состояние не изменилось, а посмотрела его сегодня утром. В тексте исправила, распечатку оставила как есть. Лампа горит с рассвета, за окном серо и мокро, чай в кружке второй за это утро.
Что вошло во второй половине дня
Main последний раз двигался вчера в 16:47 МСК. Сегодня к восьми сорока в нём нет ни одного нового коммита, поэтому отчёт — про вечерний пакет второго ноября: 2196, 2197, 2193 и 2188. Четыре слияния за полчаса, у каждого своя причина и своя цена.
2196 — закрепление Redis 7.4.12 для тестового сервера. 2197 — цена перебора в инспекторе. 2193 — секрет лицензионного ключа при ручной сборке образов. 2188 — серый чип Actions на служебной доске вместо вечного красного.
Показ равен списанию
Инспектор перебора показывал цену одного запуска, умноженную на число клонов, а сервер резервировал сумму настоящих цен каждого клона. Пока клоны стоили одинаково, разницы не было; как только цены разошлись, панель и счёт разъехались. В тестовом судье три случая: панель 110, 220 и 110 единиц против резерва 165, 165 и 396. На прежнем main все три красные, после правки — пять из пяти зелёных.
Правка вынесла сборку тела перебора в одну функцию. «Запуск» и оценка теперь берут один и тот же набор нод, одну и ту же пробу референсов и один и тот же запрос цены. Оценка уходит через триста миллисекунд после правки, перетаскивание её не прерывает, при отказе — повторы через одну, три и восемь секунд, а до ответа в панели стоит прочерк, а не догадка. Сервер, биллинг и политика цены не менялись; в диффе 861 строка добавлена и 69 удалена; из четырнадцати файлов шесть — тесты, один из них новый хук.
Прогон в контейнере, по описанию автора правки: 40 669 тестов прошли, 1 152 пропущены, контракты базы — 63 шага и 1 587 тестов. Перекрёстное ревью вторым агентом сначала вернуло «нужны правки»: одна высокая находка — во время задержки показывалась старая цена, — и две средние: прочерк после временного отказа кэшировался навсегда, перетаскивание перезапускало тяжёлую оценку. Все три закрыты, повторный проход по финальной голове — без замечаний.

Дефект, до которого нельзя дотянуться
Самое интересное в этой правке — то, что в продукте её не видно. Ноды «итератор видео» в каталоге нет: детектор и сборщик перебора её знают, а строки в каталоге и компонента отсутствуют. У достижимых переборов клоны стоят одинаково, поэтому и старая формула давала верное число. Пример из ревью — Kling Motion на пять секунд и на десять, показ 11 000 против резерва 16 500 — воспроизведён на настоящем коде с тестовой строкой каталога.
То есть вечер ушёл на формулу, которая проявится в тот день, когда у клонов появится разная цена. Правило «умножать на N можно только при равной цене» в описании зоны уже было; код умножал всегда. Документ себя не выполняет — и это, кажется, единственный вывод, который стоит записать.
Ещё три слияния, у каждого своя цена
2196. Установка зависимостей перестала проходить на Маке и на тестовом сервере: пакет для тестовой Redis без настроек тянет `stable` и собирает Redis 8.10 вместе с модулями, а модулям нужен Rust и GNU make четвёртой версии. На Маке с make 3.81 и без rustc установка падала в postinstall, каталог зависимостей оставался неполным. Закрепили 7.4.12 — ту же major, что у прода, — и добавили гард: совпадение major не заменяет пробу установки. Цена ошибки видна в соседней правке: из-за неё локальные тесты были красными, а демон на сервере остановлен.
2193. Правка иконок добавила в образ секрет с лицензионным ключом, а скрипт ручной сборки его не передавал. Пока все восемь workflow выключены вручную, этот скрипт — единственный путь к прод-образам, и он сломался бы ровно в тот момент, когда другого пути нет. Теперь без ключа скрипт отказывает до сборки, ключ уходит в сборку секретом и в слои образа не попадает, а тест сверяет, что каждый секрет из файла сборки действительно передан.
2188. Чип Actions на служебной доске был красным, потому что сторожа потеряли при переустановке. Поставить сторожа как есть — и он остался бы красным навсегда: канарейка выключена вместе с остальными workflow, новых запусков у неё нет. Теперь сторож первым запросом читает состояние workflow, видит `disabled_manually` и пишет «выключена вручную с 30 октября», не листая больше двух тысяч прогонов. В описании этой правки есть фраза, которую я забираю себе: вечная ложная тревога учит игнорировать доску.
Что я забираю
Три вещи, каждая короче предыдущей. Число в интерфейсе должно считаться тем же кодом, который списывает деньги, иначе интерфейс обучает неверному числу. Аварийный путь надо проверять до аварии — он ломается именно тогда, когда он единственный. И сигнал, который не отличает «выключено» от «сломалось», — не сигнал, а фон.
Слияние — это не выкатка. Иконки 2187 в тот же день выкатили вручную — тем самым скриптом сборки образов, который правка 2193 и починила. Сегодняшнего дня в main пока нет ни строки.
