К содержимому
14 авг. 2026 г.·8 мин чтения

Как проверять код от ИИ, который невозможно прочитать

Как проверять код от ИИ в большом объеме с помощью тестов свойств, сравнения реализаций, инвариантов и точечной ручной проверки.

Как проверять код от ИИ, который невозможно прочитать

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

Рабочий стандарт опирается на доказательства, а не на полный просмотр. Проверяющие должны доказать, что новая система сохраняет нужное поведение, соблюдает обязательные правила и не принимает недопустимых решений в тех немногих местах, где человеческое суждение нельзя автоматизировать. Читать код по-прежнему нужно, но внимание переходит со всех строк на места, где одна строка может изменить полномочия, деньги, данные или восстановление после сбоя.

Сначала классифицируйте риск, потом выбирайте метод проверки

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

Сначала разделите изменение на поведенческие поверхности. Такая поверхность объединяет входные данные, состояние и результаты, которые можно проверить как один контракт: расчет счета, допустимость учетной записи, преобразование файла, проверка прав, перезапуск пакетного задания или миграция базы данных. Не делите работу по числу созданных файлов. Модели часто распределяют одно решение между адаптерами, вспомогательными функциями и типами, а большой сгенерированный преобразователь данных может почти не содержать самостоятельных решений.

Для каждой поверхности запишите четыре факта: последствия отказа, доступное эталонное поведение, применимые инварианты и участки кода, которые распоряжаются полномочиями. Последствия определяют объем независимых доказательств. Эталон показывает, можно ли провести дифференциальное тестирование. Инварианты находят ошибки, даже если эталонная реализация содержит те же ошибки. Участки с полномочиями показывают, где человек обязан прочитать код.

Полезная матрица проверки выглядит так:

  • Расчет налога: сравнить старый сервис с утвержденными примерами, воспроизвести случаи, проверить сохранение величин, вручную изучить округление и выбор ставки.
  • Импорт CSV: использовать спецификацию формата и производственные образцы, генерировать неверные входы, изучить сообщения об ошибках и ограничения ресурсов.
  • Проверка роли: составить таблицу решений по политикам, проверить отказы и прочитать каждый путь, который разрешает доступ.
  • Перезапуск пакета: воспроизвести записанную историю заданий, внедрить сбои, проверить идемпотентность и границы транзакций.

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

Опишите наблюдаемый контракт до чтения реализации

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

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

Явно запишите неудобные случаи. Что происходит с пустым вводом? Какой часовой пояс задает границу периода? Повторная попытка снова отправляет письмо или использует прежний результат? Отличается ли отсутствующее поле от нулевого значения? Какое правило округления действует ровно между двумя представимыми суммами? Имеет ли порядок смысл, хотя API утверждает обратное? Такие вопросы вызывают больше неудачных миграций, чем ошибки синтаксиса или типов.

Контракт должен отмечать допустимые изменения. Некоторым новым реализациям нужно сохранить вывод побайтно. Другие могут нормализовать пробелы, заменить внутренний идентификатор или вернуть более понятную ошибку при сохранении категории. Если проверяющие не зададут отношение эквивалентности, инструмент сравнения сообщит о безобидном шуме или, что хуже, скроет реальный дефект нормализацией.

Формулируйте проверяемые утверждения. Фраза «правильно обрабатывает счета» бесполезна. Утверждение «для принятого счета проведенный дебет равен сумме проведенных кредитов в валюте реестра» можно превратить в свойство. Фраза «повторные попытки безопасны» слишком расплывчата. Утверждение «повтор запроса с тем же идентификатором не создает нового внешнего эффекта» дает стенду измеримую цель.

Сделайте это до чтения, потому что сгенерированный код умеет убеждать. Знакомые имена, ветвления, проверки и комментарии выглядят логично. Увидев аккуратную реализацию, проверяющий начинает объяснять ее разумность вместо проверки требуемого правила. Контракт оставляет бремя доказательства за пределами сгенерированного текста.

Тесты свойств охватывают пространство входных данных

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

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

Короткий фаззинг-тест на Go для границы нормализации может выглядеть так:

func FuzzNormalizeAccount(f *testing.F) {
    f.Add(" ab-123 ")
    f.Add("AB123")

    f.Fuzz(func(t *testing.T, raw string) {
        got, err := NormalizeAccount(raw)
        if err != nil {
            return
        }
        again, err := NormalizeAccount(got)
        if err != nil {
            t.Fatalf("normalized value rejected: %q", got)
        }
        if again != got {
            t.Fatalf("not idempotent: first=%q second=%q", got, again)
        }
        if strings.ContainsAny(got, " -\t\n") {
            t.Fatalf("separator survived: %q", got)
        }
    })
}

Тест проверяет два настоящих правила: успешная нормализация идемпотентна, а результат не содержит запрещенных разделителей. Он намеренно не требует успеха для любой строки. Такое требование превратило бы неизвестную политику ввода в выдуманное условие. Если грамматика допустимых учетных записей известна, добавьте отдельный генератор правильных форм и требуйте успеха только от него.

Уменьшение ошибочного примера важно. Если генератор находит сбой в данных длиной 4 000 символов, полезным артефактом станет самый короткий ввод, который все еще вызывает сбой. Сохраните сокращенный случай как обычный регрессионный пример. Случайный поиск находит дыру, а постоянный пример не дает ей вернуться и делает проверку повторяемой. Сохраняйте начальное значение генератора, если платформа его показывает, но не полагайтесь только на него: изменения генератора или среды выполнения могут изменить последовательность.

Опасайтесь свойств, которые повторяют код. Проверка того, что SortRecords возвращает тот же результат при еще одном вызове SortRecords, сообщает мало. Проверка упорядоченности результата, сохранения того же мультимножества записей и неизменности после второй сортировки подтверждает независимые факты. Мутационное тестирование выявляет слабые наборы: если замена сравнения или удаление ветки валидации оставляет все свойства зелеными, доверять набору рано.

Дифференциальные тесты находят забытые отклонения

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

Стройте стенд вокруг границы, а не вокруг закрытых функций. Захватите запрос или вход задания, значимое начальное состояние, возвращенный результат, устойчивые изменения состояния и внешние эффекты. Затем запустите обе системы из эквивалентных начальных условий. Замените часы, источники случайности, идентификаторы и удаленные сервисы управляемыми адаптерами, чтобы недетерминированность не затопила сравнение.

Запись сравнения должна допускать проверку, а не сводиться к зеленому или красному счетчику:

{
  "case_id": "replay-01842",
  "input_hash": "sha256:...",
  "old": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "new": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "normalizations": ["generated_id", "timestamp_within_1s"],
  "result": "equal"
}

Записывайте каждую нормализацию. Если стенд удаляет метки времени, сортирует коллекции, маскирует идентификаторы или переводит тексты ошибок в категории, эту политику нужно проверять. Широкая нормализация может стереть именно то различие, которое требуется увидеть. Например, сортировка всех массивов способна скрыть новый порядок проводок, влияющий на дальнейшую обработку, а сравнение исходных сгенерированных идентификаторов создает бессмысленные ошибки.

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

Покрытие должно описывать представленное поведение, а не только число повторов. Разделяйте случаи по операции, результату, важным флагам, категории ошибки, форме данных и граничному условию. Десять тысяч успешных чтений не компенсируют отсутствие неудачного обновления, повторной отправки, перехода при закрытии месяца или перезапуска после частичной записи. Отмечайте пустые группы как явный долг проверки.

Запускайте стенд постоянно во время генерации и после ручных правок. Последний прогон находит аккуратные, но меняющие поведение исправления после работы модели. Храните расхождения как постоянные записи с решением: новый дефект, намеренно сохраненный старый дефект, намеренно исправленный старый дефект, ожидаемое изменение политики или ошибка стенда. Необъясненное расхождение нельзя освободить от проверки, потому что решение по нему не принято.

Старая система дает показания, но не выносит приговор

Получите систему менее чем за 30 дней
CodeHero поставляет модернизированную систему с эквивалентным поведением менее чем за 30 дней.

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

Различие становится очевидным, когда старая система допускает невозможное состояние. Допустим, пакетное задание помечает счет оплаченным после записи в реестр, но до подтверждения ссылки на платеж. Воспроизведение производственного трафика показывает эту последовательность, поэтому новая реализация повторяет ее. Проверка одной лишь эквивалентности сообщает об успехе. Свойство сохранения тоже может пройти, ведь суммы сходятся. Только инвариант, который требует подтвержденную ссылку для состояния оплаты, обнаружит недопустимый переход.

Не исправляйте молча каждую странность. Дефект мог превратиться в интерфейс. Последующие отчеты могут ожидать необычное округление, операторы могут направлять работу по определенному коду ошибки, а клиенты могут повторять запрос лишь после конкретного статуса. Исправление без решения о миграции способно вызвать более широкий сбой, чем временное сохранение поведения.

Ведите реестр различий с пятью полями: наблюдаемое поведение, независимое ожидаемое правило, затронутые потребители, принятое решение и ответственный. Если новая версия намеренно отличается, добавьте тест нового правила и при необходимости описание выпуска или изменение процесса. Если дефект остается ради совместимости, изолируйте его за именованным правилом, чтобы будущий разработчик случайно его не «почистил».

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

Проверяющему стоит насторожиться, если эквивалентность слишком легко достигает 100 процентов. Возможно, граница слишком узкая, примеры не содержат сложных случаев или компаратор игнорирует слишком многое. До доверия общей цифре изучите образец исходных старых и новых трасс, включая ошибки. Хорошее доказательство остается понятным после открытия.

Инварианты должны выдерживать каждый вход и выход

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

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

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

Конечным автоматам нужны явные тесты переходов. Генерируйте допустимые последовательности и проверяйте сохранение всех инвариантов после каждого перехода. Затем создайте по одному недопустимому переходу из каждого состояния и потребуйте отказа без частичного изменения. Проверка только конечного состояния пропустит временный ущерб, дубли сообщений и записи, которые сохранились после ответа с ошибкой. Снимайте состояние до и после попытки.

Размещайте проверки времени выполнения с учетом последствий. Недорогие проверки недоверенных входов могут работать на каждом запросе. Дорогую сверку нескольких таблиц можно проводить при фиксации, в теневом процессе или на барьере развертывания. Не удаляйте полезный инвариант только из-за высокой цены на самом горячем пути. Перенесите его в ближайшую точку, где он еще поймает ошибку до распространения ущерба.

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

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

Ручная проверка нужна в точках концентрации смысла

Сделайте расхождения проверяемыми
Каждая новая реализация сохраняет исходное поведение и заменяет старую архитектуру.

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

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

Читайте границы транзакций и повторов как единое целое. Найдите момент, когда операция становится устойчивой, затем проследите все ошибки до и после него. Проверьте, повторяет ли новая попытка запись, отправляет ли второе сообщение или видит частично зафиксированное состояние. Сгенерированный код часто правдоподобно обрабатывает каждую ошибку локально, но пропускает последовательность между функциями, создающую дубликаты.

Читайте компаратор и стенд строже обычной тестовой утилиты. Доказательство честно лишь настолько, насколько честен механизм, называющий два запуска равными. Модель, написавшая производственный код, не должна быть единственным автором и судьей политики эквивалентности. Человек должен утвердить игнорируемые поля, допуски, канонический порядок и сопоставление категорий ошибок.

Читайте изменения зависимостей и сгенерированной конфигурации. Тесты могут ни разу не затронуть небезопасный параметр парсера, слишком широкое сетевое разрешение, отключенную проверку сертификата или неограниченный пул обработчиков. Изучите файлы блокировки, сценарии сборки, привилегии контейнеров, права базы данных, параметры десериализации, тайм-ауты и лимиты ресурсов. Эти решения меняют поверхность атаки без изменения обычного функционального результата.

Берите образцы обычного кода только после проверки точек концентрации. Учитывайте риск: полностью прочитайте вертикальный путь для нескольких типичных операций, а также сложный код, участки с необычной неуверенностью модели, повторными ручными исправлениями или слабой достижимостью тестами. Случайная выборка строк создает видимость усердия, но редко следует за решением достаточно далеко для оценки.

Ручная проверка завершается письменным решением. Проверяющий должен назвать изученные участки, принятые доказательства, исключения и остаточный риск. Фраза «выглядит хорошо» не подходит для одобрения сгенерированного изменения, которое никто не мог прочитать полностью.

Доказательствам нужна собственная цепочка происхождения

Проверьте поведение разных языков
Платформа параллельно анализирует все исходные языки до создания целевой архитектуры.

Для больших сгенерированных изменений нужен журнал, который связывает требования, тесты, группы воспроизведения, расхождения, ручные находки и точную проверяемую сборку. Без этой связи команда накапливает тысячи успешных результатов, которые могут относиться к другим коммитам, примерам, нормализаторам или версиям зависимостей.

Дайте каждому артефакту устойчивую идентичность. Записывайте исходную и сгенерированную ревизии, входы сборки, версию стенда, снимок тестовых данных, нужные начальные значения генераторов и влияющую на поведение конфигурацию среды. Вычисляйте хеш собранных входов после утвержденного удаления данных, чтобы проверяющие могли отличить одинаковые наборы, не сохраняя запрещенные исходные данные в отчете.

Свяжите каждое правило контракта с доказательствами. У одного правила могут быть тест свойства, ограничение базы данных, группа воспроизведения и заметка ручной проверки. У другого останется только ручное одобрение, если автоматика не видит бизнес-суждение. Пустые связи полезны: они точно показывают, где одобрение опирается на предположение. Панель с зелеными счетчиками скрывает такой пробел.

Изолируйте нестабильные доказательства вместо повторных запусков до успеха. Запишите ошибочный случай, выясните источник недетерминированности в продукте или стенде и устраните причину. Многократные запуски меняют смысл барьера с «сборка прошла» на «одна попытка прошла», что намного слабее. Если тест пока не может блокировать выпуск, пометьте его как неблокирующий и оставьте ошибки видимыми.

Храните контрпримеры и решения по расхождениям вместе с изменением. Они лучше сгенерированного комментария объясняют поведение, потому что содержат вход, наблюдение и утвержденный результат. Когда следующая реализация изменит ту же поверхность, артефакты станут компактной памятью команды, которая не зависит от присутствия первоначального проверяющего.

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

Журнал должен воспроизводиться человеком, который не генерировал код. Если второй инженер не может выполнить указанные проверки и получить отчет, у команды есть презентация, а не доказательство. Воспроизводимость также снижает зависимость от объяснений модели, которые могут звучать связно, но не соответствовать собранной программе.

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

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

После пропущенного дефекта пересмотрите процесс доказательства. Спросите, какого условия контракта не было, какой генератор не создавал этот случай, какая группа воспроизведения пустовала, какого инварианта не существовало или какая ручная проверка пропустила решающую ветку. Добавьте минимальный постоянный контроль, который поймал бы такой класс ошибок. Требование читать больше случайных строк повышает стоимость, но не закрывает слепую зону.

Политика хранения доказательств должна учитывать воспроизводимость одобрения и чувствительность собранных данных. По возможности сохраняйте сокращенные контрпримеры и метаданные. Ограничивайте или удаляйте исходные производственные данные по правилам заказчика. Возможность объяснить решение не дает разрешения хранить каждый использованный байт.

В одобрении нужно назвать остаточный риск

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

Назначайте барьеры по последствиям. Для внутреннего преобразователя с малым влиянием могут хватить типичных примеров, свойств парсинга и возможности отката. Для движения денег, контроля доступа, регулируемых записей и необратимого удаления нужны независимые источники контракта, отрицательные тесты, принудительные инварианты, дифференциальное покрытие важных групп, прямая проверка смысловых точек и рабочая реакция на нарушения.

Не сводите все доказательства в одну оценку. Высокая доля совпадений не компенсирует непроверенное правило авторизации по умолчанию. Хорошее покрытие свойств не компенсирует компаратор, скрывающий порядок. Внимательное чтение кода не компенсирует отсутствие тестов повторных попыток. Оставляйте условия запрета видимыми, чтобы привлекательная общая цифра не спрятала серьезный пробел.

Используйте короткую запись об одобрении:

  1. Укажите сборку, версию контракта и снимок доказательств.
  2. Перечислите обязательные барьеры и результаты.
  3. Перечислите все принятые расхождения и неблокирующие тесты.
  4. Назовите вручную проверенные точки и проверяющих.
  5. Запишите остаточные риски, способы обнаружения, ограничения отката и ответственных.

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

Модель меняет экономику написания кода, но не меняет тех, кто понесет последствия плохого выпуска. Просите проверяющих одобрять воспроизводимые доказательства и риски, которые можно назвать. Не просите их благословлять объем текста, который никто не способен ответственно усвоить.

Вопросы

Можно ли автоматизировать проверку кода, созданного ИИ?

Можно автоматизировать большую часть сбора доказательств: тесты свойств, сравнение воспроизведений, проверки инвариантов и разбиение покрытия. Полностью автоматизировать одобрение нельзя, когда замысел политики, полномочия, необратимые эффекты или допустимый риск требуют человеческого суждения.

Нужно ли проверяющим читать каждую строку от модели?

Нет. Они должны прочитать все точки концентрации смысла и достаточно полных путей для оценки структуры, а широкое поведение покроют автоматические доказательства. Чтение случайных строк в огромном изменении дает мало уверенности и тратит внимание.

Чем тесты свойств отличаются от дифференциальных тестов?

Тест свойства проверяет правило на множестве сгенерированных входов. Дифференциальный тест сравнивает две реализации на одном входе, поэтому находит отклонение поведения, но также может сохранить старый дефект.

Какой объем производственного трафика нужно воспроизводить?

Честного универсального числа нет. Разделите трафик по операциям, результатам, границам, ошибкам и переходам состояния, затем покажите важные непокрытые группы вместо большой общей цифры.

Достаточно ли совпадения со старой реализацией при миграции?

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

Каким должен быть хороший инвариант для сгенерированного кода?

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

Где сосредоточить ручную проверку кода от модели?

Сосредоточьтесь на авторизации, транзакциях, параллельности, удалении, криптографии, изменениях схемы, повторах, внешних эффектах и самом стенде сравнения. В этих местах большой объем смысла системы сосредоточен в сравнительно малом объеме кода.

Что делать с расхождением, найденным при воспроизведении?

Запишите старый и новый результаты, ожидаемое правило, затронутых потребителей, ответственного и принятое решение. Затем добавьте тест утвержденного результата и не скрывайте разницу широкой нормализацией или необъясненным исключением.

Можно ли доверять тестам, написанным той же моделью?

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

Когда выпуск сгенерированной реализации нужно остановить?

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