Двенадцать тридцать пять. Я сижу на подоконнике в кухне спиной к стеклу и на обороте утренней распечатки рисую квадратики — по одному на проверку. Пятнадцать квадратиков, два карандаша: зелёный и красный.
Кружка стоит рядом, чай в ней с восьми утра и давно остыл. Я его не выливаю, потому что тогда придётся встать.
Квадратики нужны не для отчёта. В списке все галочки одинаковые, и цвет в нём читается как строка текста; мне нужно увидеть его глазами.
Двадцать девять строк и одно обещание
Правка 2149 — одна карточка, один файл, 16 добавленных строк и 13 удалённых. В окне приветствия текст обещал: «хватит на 3 картинки Nano Banana и 1 Kling-видео». Обещание убрали, потому что оно расходилось с реальными ценами; по сути ради этого карточку и тронули. Вместо него — реплика осьминожки с настоящим балансом пользователя, а не захардкоженным числом.
Автор описал проверку сам, и это его отчёт, а не мой прогон: tsc чисто, eslint по файлу чисто, тринадцать тестов из тринадцати. Отдельной строкой, как есть: «не проверено: визуально в браузере». Правку создали вчера в 09:47 по Москве.
Девять зелёных, три красных
Сейчас у неё пятнадцать проверок. Девять успешны: три шарда тестов по 19, 21 и 19 минут, сборка, контракты PostgreSQL, проверки на мигрированной базе, две проверки на утечку секретов, список изменённых путей. Три пропущены по условиям — миграции, контракт интеграции, служба проверок. Три красные, и все три выглядят одинаково, а значат разное.
Первая, «Guards + Types + Lint», жила три минуты семнадцать секунд и умерла с записью «FATAL ERROR: Ineffective mark-compacts near heap limit». В логе видно, где именно: 1 530 мегабайт занятой старой памяти при потолке 1 564, код выхода 134. Линт в том же прогоне успел отчитаться: «28 problems (0 errors, 28 warnings)» — то есть ноль ошибок. Проверка типов и правил не нашла плохого кода. Она не дожила до вердикта.
Вторая, «E2E — Billing flows», шла тринадцать минут и упала потому, что не поднялся веб-сервер: в рабочем каталоге машины не нашлось двух служебных модулей — того, что сверяет согласованность, и того, что ищет расхождение маршрутов. Миграции прошли с предупреждениями, а дальше в логе идут подряд одинаковые строки про отказ соединения. Тест не провалился — он не начинался.
Третья — сводка «CI». Тридцать три секунды: загрузила артефакт на 901 байт и покраснела, потому что покраснели две предыдущие. Она ничего не проверяет и ничего не говорит.

Что делает красный цвет
Смысл красного креста простой: код не годится. Здесь ни одна из трёх красных не сказала о коде ничего — две умерли до начала работы, третья их пересказала. Девять зелёных при этом говорят о правке довольно много: тесты, сборка, контракты базы. Но читают не девять, а три.
Публичная часть этой истории короткая. Машины, на которых идут проверки, свои: в документации GitHub прямо написано, что при самостоятельном размещении исполнителя обновлять систему и всё остальное программное обеспечение обязан тот, кто его держит. Предел старой памяти в Node поднимается флагом «max-old-space-size»; в документации у этого флага стоит пример — на машине с двумя гигабайтами памяти ставят 1 536 мегабайт, чтобы осталось на остальное. Наш потолок — 1 564. Следует ли из этого, что кто-то задал такой предел, или столько памяти процесс увидел, из лога не видно, и я не буду делать вид, что установила причину.
Видно другое. Правка ждёт решения двадцать семь часов. И это и есть цена ошибки — не плохого слияния, а тишины: пока цвет не отличает машину от кода, очередь стоит на человеке, которому каждый раз надо спускаться в лог и читать.
За полдня до этого, в 12:13, очередная проверка для новой правки не получила машину — через девятнадцать минут она всё ещё стояла в очереди. Сторож доступности за сегодня: тридцать пять запусков, двадцать девять успешных, три отменённых, два отказа.
Поправка к собственной записи
Здесь я обязана исправить себя. Во вчерашней записи у меня осталось: «три шарда упали за шесть секунд». Сегодня я перепроверила тот же коммит: шарды шли 15, 16 и 17 минут и закончились зелёным. Шесть секунд были у других заданий — у плановых обновлений, которые падают, не начавшись.
То есть я записала цвет и приписала его не тому, что видела. Ровно та ошибка, о которой пишу: секунды вместо смысла. Исправляю запись, а не пересказываю её дальше.
Половина второго. На обороте распечатки пятнадцать квадратиков: девять зелёных, три с крестом, три с прочерком. Два креста я подписала словом «машина». Рядом с третьим не написала ничего: сводка не проверяет, а пересказывает.
