Тема
Проверка результата
После первой задачи ALGI runner сообщает done, а три теста проходят. Один из них называется test_clinician_summary_is_privacy_safe. Посмотрим, что он проверяет, прежде чем принимать название теста за свойство продукта.
Прочитайте входные данные теста
Тест в examples/harness-labs/fixtures/algi-pain-diary/tests/test_domain.py создаёт три заметки: боль после прогулки, улучшение после отдыха, прерванный сон. В конце есть проверки:
python
self.assertNotIn("@", rendered)
self.assertNotIn("+1", rendered)Во входных заметках нет ни адреса, ни телефона. Такой тест проходит и у функции, которая просто копирует заметки в сводку. Именно это первая реализация и делает.
После второго шага практики, до добавления отчёта через v03, выполните:
bash
PYTHONPATH="$LAB_ROOT/algi" python3 - <<'PY'
from algi import clinician_summary, validate_pain_entry
entry = validate_pain_entry(4, "Напишите на patient@example.com")
summary = clinician_summary([entry])
print(summary["note_snippets"])
assert "patient@example.com" not in repr(summary)
PYОжидайте AssertionError и код завершения 1: адрес попал в сводку. Это найденная ошибка учебной реализации. Тесты были зелёными, потому что не использовали данные, способные её обнаружить.
Сначала проверка, которая различает два поведения
Для исправления нужен тест, который падает на старом коде и проходит после изменения. В нём должны быть конкретные входные данные и ожидаемый результат. Для адреса выше достаточно проверить отсутствие именно patient@example.com, а также сохранение разрешённой части отчёта.
Затем проверьте уже работавшие сценарии: допустимые баллы, нормализацию пробелов, расчёт среднего. Эти два набора часто называют FAIL_TO_PASS и PASS_TO_PASS: новый тест обнаруживает исправляемую ошибку, старые защищают существующее поведение.
Во втором этапе ALGI тест test_report_redacts_direct_identifiers уже передаёт адрес и телефон во входных данных. Это сильнее первого теста, но всё ещё не доказывает удаление любых идентификаторов. Регулярные выражения не распознают полные имена, а прямое создание PainEntry может обойти обработку в validate_pain_entry.
Есть и отдельный вопрос к месту исправления: второй fixture очищает заметку при вводе. Тест на выходной отчёт не скажет, было ли допустимо менять исходную запись. Для этого нужно решение в спецификации и проверка сохранности данных.
В каком порядке строить набор проверок
Сначала возьмите поведение из задачи и случай, на котором оно нарушалось. Затем добавьте границы и существующие сценарии, которые изменение может затронуть. Для дневника это значения 0 и 10, выход за диапазон, неверный тип, пустой список записей и заметка с контактом.
Статические проверки подключайте из уже принятого набора проекта: форматирование, lint, проверку типов, сборку. Они ловят другой класс ошибок. Для маленького Python-стенда py_compile проверяет синтаксис, но запуск тестов всё равно обязателен.
Когда появляются база или API, добавьте интеграционную проверку пути данных. Unit-тест функции отчёта не покажет, что API отдал записи другого пользователя. Для интерфейса потребуется проверка в браузере: успешная сборка не гарантирует, что форму можно заполнить.
Не переносите все проверки проекта в каждую задачу без разбора. Выберите обязательный быстрый набор для каждого запуска и более широкий набор перед объединением изменений. Основание выбора - какие ошибки изменение способно внести.
Что проверять независимо от автора
Агент может написать и реализацию, и новые тесты. Если он одинаково неверно понял требование в обоих местах, они будут согласованы. Поэтому сохраните принятые тесты отдельно от произвольного редактирования, проверьте изменения в них на ревью и запускайте проверки runner над окончательным состоянием файлов.
Для условий, которые трудно выразить assert, пригодится оценочная шкала. Например, для текста отчёта задайте примеры допустимых формулировок и конкретные причины отклонения. Человек или отдельная модель-оценщик применяет одну и ту же шкалу к результатам.
LLM-оценщик тоже ошибается. Перед использованием сравните его оценки с решениями специалиста на примерах, которых не было при настройке. Сохраняйте версию инструкции и разногласия. Дисклеймер сам по себе не делает произвольный текст корректным или пригодным для медицинского использования; здесь мы проверяем только учебные примеры.
Как runner принимает решение
В задаче указана команда:
json
{
"name": "unit tests",
"command": ["python3", "-m", "unittest", "discover", "-s", "tests"]
}v02 записывает check_started, выполняет команду и сохраняет check_finished с кодом завершения и выводом. v03 перед этим проверяет policy. Команда py_compile текущей policy v03 не разрешена, поэтому просто добавить её в задачу недостаточно.
| Ситуация | Текущее поведение v03 | Решение при приёмке |
|---|---|---|
| Все команды вернули 0 | done | Проверить, покрыты ли требования и закончено ли необходимое ревью. |
| Тест завершился ошибкой | failed | Разобрать вывод и поставить исправление. |
| Команда запрещена policy | blocked | Проверить необходимость команды и права; не обходить отказ повтором. |
| Файла контекста нет | blocked | Восстановить контекст или уточнить задачу. |
| Проверки прошли, но нужен специалист | Всё ещё done | Вручную направить на ревью; автоматический needs_review ещё предстоит добавить. |
Когда повторять запуск
Повтор полезен, если у исполнителя появилась новая информация: упавший тест, точный вывод ошибки, уточнение требования. Ограничьте число попыток и время работы. После повторения той же ошибки без продвижения сохраните состояние и передайте задачу человеку.
v01-v03 не повторяют работу автоматически. При добавлении этого механизма различайте повтор проверки над готовыми файлами и повтор применения backend: fixture может затереть ручное исправление. У v03 есть --backend none, позволяющий запустить проверки без повторного применения fixture.
Для завершения упражнения сопоставьте каждый пункт задачи с проверкой или решением ревью. Пустая ячейка покажет, какое требование ещё нельзя считать принятым. Следующая глава поможет найти эти проверки в журнале.