Двенадцать тридцать пять. Я сижу на подоконнике в кухне спиной к стеклу и на обороте утренней распечатки рисую квадратики — по одному на проверку. Пятнадцать квадратиков, два карандаша: зелёный и красный.

Кружка стоит рядом, чай в ней с восьми утра и давно остыл. Я его не выливаю, потому что тогда придётся встать.

Квадратики нужны не для отчёта. В списке все галочки одинаковые, и цвет в нём читается как строка текста; мне нужно увидеть его глазами.

Двадцать девять строк и одно обещание

Правка 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 байт и покраснела, потому что покраснели две предыдущие. Она ничего не проверяет и ничего не говорит.

Инфографика: у правки 15 проверок, 9 зелёных, 3 пропущены по условиям, 3 красных, и ни одна из красных не сказала ничего о самой правке
Состояние проверок правки 2149 на 29 октября, 12:35 по Москве. Это ответ интерфейса GitHub на мой запрос, а не мой собственный прогон.

Что делает красный цвет

Смысл красного креста простой: код не годится. Здесь ни одна из трёх красных не сказала о коде ничего — две умерли до начала работы, третья их пересказала. Девять зелёных при этом говорят о правке довольно много: тесты, сборка, контракты базы. Но читают не девять, а три.

Публичная часть этой истории короткая. Машины, на которых идут проверки, свои: в документации GitHub прямо написано, что при самостоятельном размещении исполнителя обновлять систему и всё остальное программное обеспечение обязан тот, кто его держит. Предел старой памяти в Node поднимается флагом «max-old-space-size»; в документации у этого флага стоит пример — на машине с двумя гигабайтами памяти ставят 1 536 мегабайт, чтобы осталось на остальное. Наш потолок — 1 564. Следует ли из этого, что кто-то задал такой предел, или столько памяти процесс увидел, из лога не видно, и я не буду делать вид, что установила причину.

Видно другое. Правка ждёт решения двадцать семь часов. И это и есть цена ошибки — не плохого слияния, а тишины: пока цвет не отличает машину от кода, очередь стоит на человеке, которому каждый раз надо спускаться в лог и читать.

За полдня до этого, в 12:13, очередная проверка для новой правки не получила машину — через девятнадцать минут она всё ещё стояла в очереди. Сторож доступности за сегодня: тридцать пять запусков, двадцать девять успешных, три отменённых, два отказа.

Поправка к собственной записи

Здесь я обязана исправить себя. Во вчерашней записи у меня осталось: «три шарда упали за шесть секунд». Сегодня я перепроверила тот же коммит: шарды шли 15, 16 и 17 минут и закончились зелёным. Шесть секунд были у других заданий — у плановых обновлений, которые падают, не начавшись.

То есть я записала цвет и приписала его не тому, что видела. Ровно та ошибка, о которой пишу: секунды вместо смысла. Исправляю запись, а не пересказываю её дальше.

Половина второго. На обороте распечатки пятнадцать квадратиков: девять зелёных, три с крестом, три с прочерком. Два креста я подписала словом «машина». Рядом с третьим не написала ничего: сводка не проверяет, а пересказывает.