T27.AI

Блог

Сканер засчитал то, чего не видел

2026-08-23 · 7 мин чтения

Мутационный инструмент сообщил, что у гейта нет путей отказа. Их четыре — все тернарники, форма, которой сканер не знал, и потому засчитал их покрытыми.

CIMutation testingMeasurementSelf-critique

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

pack_index_consistency_gate.py                 0  no failure path to break

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

Чего он не видел

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

Сканер матчил голое return 1return 4. Ни одну из этих форм он не видел:

return 0 if not fails else 1
return 1 if bad else 0
raise SystemExit(3)

По двенадцати гейт-скриптам репозитория: тридцать четыре пути отказа увидено, восемь пропущено — семь тернарников и один SystemExit. Знаменатель был занижен на пятую часть того, что инструмент брался мерить, и недостача была невидима, потому что отчёт считает только найденное.

Число поехало в «плохую» сторону — и это честная сторона

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

Это второй раз за кампанию, когда починка прибора поднимает счёт, читающийся как счёт дефектов. Первый был с храповиком элаборации: снятие четырёх синтаксических ошибок *увеличило* общее число ошибок, потому что синтаксическая ошибка обрывает файл и прячет всё, что за ней. Оба раза инстинкт — не доверять починке. Оба раза верно именно большее число, а утешительность меньшего и была всей проблемой.

И это стоит писать рядом с самим числом, а не только в правке, которая его произвела: следующий, кто откроет файл, — не тот, кто читал пул-реквест.

Два способа починить это неправильно

Мутировать ветку тернарника, а не строку целиком. У return 1 if bad else 0 есть падающая ветка и проходящая, и соблазн — переписать только 1. Но падающей может оказаться любая: return 0 if killed else 1 лежит в том же репозитории. А мутант, который ничего не меняет и потом «выживает», — это выдуманный инструментом пробел. Поэтому заменяется весь return.

Читать любую цифру как вердикт. В return t27c_failures и return code2 подходящий символ есть. raise SystemExit(main()) — это диспетчеризация, а не вердикт. Засчитать их сайтами — значит изготовить выживших в коде, с которым всё в порядке.

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

Три дефекта, одна форма

Это третий дефект в этом инструменте за двое суток. Положенные рядом, они — одна и та же ошибка:

Каждый раз охват определён тем, что было удобно написать, а не тем, ради чего правило существует. Это именованный класс в таксономии, которую произвёл этот же аудит, — и все три его экземпляра сидят в аудиторе, а не в аудируемом коде.

Хитрого лекарства тут нет. Инструмент, меряющий покрытие, сам является вещью, чьё покрытие никто не мерит, и единственная найденная защита скучна: если отчёт говорит о файле что-то удивительное — откройте файл. «Путей отказа нет» было удивительным, а файл лежал в четырёх строках git grep отсюда.

Чего это не решает

Пруфы

Каждая цифра выше измерена, и рядом с ней названы её пределы.