Признак приёмки и то, что он утверждает на самом деле
Разница между «сделал» и «работает» держится на подмене: вместо состояния объекта проверяется соседний признак, который почти всегда совпадает с ним — и потому не вызывает подозрений в тот единственный раз, когда не совпал.
| Признак «готово» | Что он утверждает | Дешёвая проба состояния |
|---|---|---|
| Карточка в статусе «сделано» | кто-то дошёл до задачи и что-то в ней написал | слушается ли порт, дата последней записи в базе, ушло ли сообщение адресату |
| Выкатка была после коммита | в тот час выкатка была | в логе выкатки перечислены пути — нужный файл в списке есть или нет |
| Скрипт запускается из консоли | код в принципе рабочий | запуск через штатный планировщик и его собственный итоговый код |
| В логе нет ошибок | в лог никто не писал | время изменения результата свежее, чем период запуска |
Карточка закрыта, объект мёртв
Задача «перезапустить сборщик» стояла в статусе «сделано», а в заметке к ней лежал диагноз: процесса нет, порты не слушаются. Проверка состоянием показала, что сборщик мёртв 10 дней: последняя запись в базе — 21.07 в 12:27, портов в списке слушающих нет. Соседняя карточка того же вида: «ответить тем, кому не ответили» закрыта, внутри — составленный список 9 заказчиков без ответа, а ответили им или нет, доска не знает в принципе.
Механика. Слово «сделано» у задач вида «почини X» и «ответь X» означает «расследование выполнено», а не «дефект устранён». Для владельца обе карточки выглядят одинаково закрытыми, и именно поэтому диагноз обязан заводиться отдельной находкой, а исходная задача — оставаться открытой со ссылкой на неё.
Пробы состояния здесь стоят секунды и не зависят ни от чьей формулировки: время изменения рабочего файла базы, порт в списке слушающих, дата последней записи. Ни одна из них не читает карточку.
Выкатка была — но не эта
По инциденту «заявки не уходят в мессенджер» приёмка стояла в жёлтом: фикс в общей ветке есть, выкатка после него была, доказательства нет. Разбор логов: выкаток за тот час восемь, семь из них катили доску, админку и страницы коммерческих предложений. Фикс уехал ровно одной — коммит в 14:31:15Z, ран в 14:36:46Z, и только в его списке путей есть файл обработчика заявок.
Совпадение по времени не доказывает ничего, потому что выкатка у нас адресная: катится перечисленное, а не «всё, что накопилось». Признак приёмки поэтому один — строка со списком путей в логе конкретного рана.
- Ран завершился успешно.
- Время рана позже коммита с фиксом.
- Нужный файл присутствует в перечне путей этого рана.
Отсутствие любого из трёх условий означает, что выкатки не было. Два из трёх — тоже не было: именно так семь чужих выкаток изображали доставленный фикс.
Автомат сломался и молчит
Сбор материалов для внутреннего радара стоял с 22.07, и это не насторожило никого. Причин оказалось четыре, независимых друг от друга:
- Расхождение форматов. Разбор дописывал записи с одним ключом, сборщик читал другой и падал на каждом прогоне до первого источника. Аварийный след уходил в поток планировщика мимо файла лога, поэтому в логе оставались две строки — тишина выглядела как «нового не выходило».
- Планировщик отклонял запуск. Политики «не запускать от батареи» и «только интерактивно» дали отказ 30.07. Собственное поле результата у задачи планировщика никто не смотрел.
- Впустую потраченное время. Определение идентификатора канала уводило загрузчик на страницы мессенджера по 120 с на каждом прогоне.
- Троттлинг принят за смерть источников. 21.07 семнадцать каналов ответили 500 и 404 на опрос пачкой без пауз, итог «собрано 1 видео» прочитался как успех. Сегодня те же адреса отдают 200 — каналы были живы, и их едва не выключили из реестра.
Проверять надо свежесть, а не успех. Время изменения результата старше периода запуска = автомат мёртв, что бы ни было написано в логе. Признак работает даже когда лог пустой, красивый или отсутствует.
Прогон делался через тот механизм, которым задача запускается на самом деле, а не из консоли: запуск руками отработал бы и при выключенной задаче планировщика, и отказ остался бы незамеченным. После починки поле результата у задачи стало нулевым (было отрицательное), опрос дал 23/23 + 6/6 + 12/12 каналов и 81 материал за прогон.
Отдельно проверялся провальный путь: подставной реестр из двух заведомо мёртвых каналов дал «ПРОВАЛ: 2 из 2» и ненулевой код выхода. Без такой пробы «зелёный» прогон означал бы только то, что в этот раз ничего не сломалось.
Что мы из этого сделали
- У задач вида «почини» приёмка — состояние объекта. Порт, время изменения файла, дата последней записи. Статус карточки к приёмке не допускается.
- Диагноз — это отдельная находка, а не закрытие исходной задачи.
- Доставка подтверждается адресным признаком: файл в перечне путей конкретного рана, а не хронологией «коммит, потом выкатка».
- Автоматика принимается двумя прогонами — штатным механизмом запуска и заведомо провальным входом, чтобы увидеть, как она сообщает о провале.
Все четыре пробы вместе занимают минуты и не требуют доступа ни к чьим отчётам — в этом их ценность: они не зависят от того, кто и как описал свою работу.