Начисление очков починили. В ответе лежат терминальный вывод, скриншот табло и короткое "готово", файлов много, а вопрос простой: что из этого отвечает на требование задачи?

Свидетельство - это не любой файл, оказавшийся рядом с исправлением. Это результат конкретной проверки, по которому видно, что проверяли, на каком состоянии кода и что при этом получилось. Разные материалы отвечают на разные вопросы, и ни один не отвечает на все сразу.

Разберём, как превратить требование в проверяемое утверждение, что записать о прогоне команды, что подтверждает лог, что diff и что кадр экрана. Потом сложим это в короткий журнал EVIDENCE_LOG из шести полей и разберём готовый набор материалов на достаточность.

Критерий задаёт проверку

Сквозной пример на всю статью: небольшая бонус-игра со счётом на табло. Счёт на старте 0, три совпадения должны добавлять 3 очка, а до исправления добавляли 30. Правило начисления придумано для этой игры - в соседнем проекте оно может быть каким угодно, переносить его туда не стоит.

Фразу "счёт исправлен" проверить нельзя: непонятно, что запускать и на что смотреть. Проверяемое утверждение собирается из трёх частей: начальное состояние, действие и ожидаемое наблюдение. Получается "при счёте 0 три совпадения добавляют 3 очка, и на табло видно 3". Теперь у утверждения есть проверка.

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

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

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

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

Команда и её результат

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

  • папка, из которой запускали команду;
  • сама команда, дословно;
  • состояние кода: до правки, после правки, с какими незакоммиченными изменениями;
  • чем закончилось: код выхода и итоговые счётчики;
  • какие проверки реально участвовали, а какие нет.

Отдельно стоит различать "нужно запустить npm test" и "запустил npm test, вот вывод". Первое - инструкция, план на будущее. Второе - факт. Вот здесь легко выдать намерение за результат, особенно когда в ответе аккуратно расписано, что следовало бы проверить.

npm test не запускает "все тесты вообще". Он выполняет то, что записано в поле test раздела scripts конкретного package.json - выбранного npm проекта. Чтобы не гадать, какой проект выбран, запускайте команду из его корня и записывайте эту папку в журнал. В соседнем проекте за тем же именем может стоять другой инструмент, другой набор шагов или ничего.

Команда заканчивается кодом выхода: 0 обычно значит "инструмент считает прогон успешным". В bash его показывает echo $? сразу после команды; в PowerShell для внешней программы вроде npm это $LASTEXITCODE. Только вот ноль не говорит, что нужный тест участвовал: его могли пропустить, отфильтровать по имени или вообще не написать. Поэтому рядом с кодом выхода всегда нужны счётчики и имя интересующего вас теста.

Что спросить у Claude Code

Просите показать фактический запуск: команду, папку и исходный вывод целиком, а отдельной строкой - что из запланированного выполнить не удалось. Команду берите из проекта, а не из общей шпаргалки: в package.json видно, что именно скрывается за npm test здесь.

Что сохранить из лога

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

✖ three matches give 3 points (2.4108ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  30 !== 3
      at TestContext.<anonymous> (src/bonus-game/score.test.js:8:10)
ℹ tests 1
ℹ pass 0
ℹ fail 1
ℹ skipped 0

Это фрагмент, полный вывод сохранён в файл, скажем logs/test-fail.txt. По этому фрагменту уже видно главное: упал именно тест про три совпадения, ожидали 3, получили 30, пропущенных проверок нет.

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

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

Что подтверждает diff

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

--- a/src/bonus-game/score.js
+++ b/src/bonus-game/score.js
@@ -1,5 +1,5 @@
-const POINTS_PER_MATCH = 10;
+const POINTS_PER_MATCH = 1;

function calcScore(matches) {
   return matches * POINTS_PER_MATCH;
}

Под таким фрагментом нужна одна строка подписи: какие состояния сравнили. Например "рабочее дерево против коммита a1b2c3d до правки, команда git diff HEAD"; идентификатор здесь учебный, в журнале нужен ваш настоящий. Такая команда сравнивает текущие отслеживаемые файлы с HEAD, включая подготовленные к коммиту изменения. Обычный git diff без HEAD показывает только разницу с подготовленным состоянием и может быть пустым уже после git add. Без подписи diff читается как "что-то с чем-то", и повторить сравнение не получится.

Отдельно сверьте, что ожидание теста осталось прежним - 3. Если вместе с кодом поменялось и ожидаемое число, это уже другая история: проверка подстроилась под поведение, а не поведение под требование.

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

Что видно на скриншоте

Состояние и действие

Кадр с числом 3 на табло подтверждает ровно одно: в момент съёмки на табло было 3. Это не то же самое, что "три совпадения добавили 3 очка". Между этими двумя утверждениями лежит всё, чего в кадре нет: с какого счёта начали и что вообще сделали.

Чтобы кадр стал свидетельством, рядом с ним записывают сценарий:

  1. что открыли: адрес страницы или способ запуска, и какая это версия - с правкой или без;
  2. начальное состояние: счёт на старте 0, старые данные не подтянулись;
  3. действие: собрали три совпадения;
  4. наблюдение: на табло 3, снято сразу после действия.

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

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

Что может прочитать модель

Картинку можно передать в сессию и попросить прочитать. Формулировка тут решает всё: просите назвать видимое число и перечислить сомнения ("видно ли начальное состояние", "понятно ли, какая это версия"), а не подтвердить заранее заданный вывод. На просьбу "подтверди, что баг исправлен" легко получить вежливое согласие, которое ничего не проверяет.

Возможность передать изображение зависит от модели и среды, в которой вы работаете. В Claude Code можно указать путь к сохранённому изображению и попросить его прочитать. Если изображение не загрузилось, сначала проверьте путь и доступность файла; одна смена модели не гарантирует исправления проблемы.

Сверяйте прочитанное с кадром

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

Один сценарий до и после

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

Работает это при одном условии: сравнивают одинаковые исходные данные и одинаковые ожидания. Тот же начальный счёт, то же число совпадений, то же ожидаемое значение 3. Вот зелёный итог того же теста после правки:

✔ three matches give 3 points (1.3983ms)
ℹ tests 1
ℹ pass 1
ℹ fail 0
ℹ skipped 0

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

И два файла с именами before.txt и after.txt сами по себе ничего не гарантируют. Имя файла - не свидетельство. Смотреть надо внутрь: одна ли там команда, один ли тест, одно ли ожидание. Контрольный возврат сломанного состояния (тот самый приём с git stash) - отдельная проверка со своими правилами, здесь достаточно знать, что красное до правки берётся из настоящего прогона, а не из памяти.

Короткий EVIDENCE_LOG

EVIDENCE_LOG - в этой статье обычный текстовый журнал из шести полей в следующем порядке: СИМПТОМ, ЛОГ-УЛИКА, ПАДЕНИЕ НА СЛОМАННОМ, ПОЧИНКА, ЧЕСТНОЕ ЗЕЛЁНОЕ, СКРИНШОТ. Так удобнее сопоставить симптом, исправление и результат. Сам порядок полей достоверность записей не гарантирует.

Всё, что мы собирали выше, раскладывается по этим полям. Команда и папка идут в поле про падение, состояния для сравнения - в починку, ссылки на полные файлы - туда, откуда они взялись. Заводить рядом ещё один пакет документов не нужно.

Ниже учебная схема заполнения: она показывает, что писать в каждом поле, а не отчитывается о выполненных проверках. В своём журнале замените текст фактическими результатами.

СИМПТОМ: в бонус-игре при начальном счёте 0 три совпадения
дают 30 очков вместо 3. Повторяется каждый раз: открыть игру,
собрать три совпадения, посмотреть на табло.

ЛОГ-УЛИКА: в выводе прогона "30 !== 3" в тесте
"three matches give 3 points", полный вывод в logs/test-fail.txt.
Отдельно, из чтения кода: в src/bonus-game/score.js
множитель POINTS_PER_MATCH равен 10. Это результат чтения кода,
в выводе теста числа 10 нет.

ПАДЕНИЕ НА СЛОМАННОМ: HEAD a1b2c3d (учебный идентификатор),
рабочее дерево чистое; в коммите сломанный расчёт и тест.
Папка - /project/bonus-game, команда - npm test.
В package.json scripts.test = node --test. Падает "three matches give 3 points",
причина "30 !== 3", tests 1, pass 0, fail 1, skipped 0, код выхода 1.
Фрагмент вывода выше, полный - logs/test-fail.txt.

ПОЧИНКА: POINTS_PER_MATCH изменён с 10 на 1 в файле
src/bonus-game/score.js; других изменений нет. HEAD тот же a1b2c3d.
Diff: git diff HEAD, рабочее дерево против этого коммита;
сохранён в diffs/score-fix.diff.
Ожидаемое значение в тесте осталось прежним - 3.

ЧЕСТНОЕ ЗЕЛЁНОЕ: та же команда npm test из той же папки на коде
после описанной правки. Тот же тест проходит: tests 1, pass 1,
fail 0, skipped 0, код выхода 0.
Полный вывод - logs/test-pass.txt.
Сценарий с пятью совпадениями не запускался.

СКРИНШОТ: screenshots/bonus-score-3.png. Игра открыта заново
по адресу http://localhost:3000 из того же рабочего дерева
после правки. Счёт на старте 0, выполнены три совпадения,
на табло 3. Сохранение результата в лидерборде не проверялось.

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

Обратите внимание на две последние строки полей 5 и 6. Пропуск отмечается прямо, одной фразой: "не запускался", "не проверялось". это не признание в лени, это граница вывода. Журнал без таких строк выглядит полнее, а на деле просто молчит о том, чего никто не делал.

Проверьте себя

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

  1. сообщение агента "готово, баг исправлен";
  2. инструкция запустить npm test;
  3. фактические прогоны одного теста: красный до правки и зелёный после;
  4. diff с изменением множителя;
  5. одиночный кадр с числом 3, без описания запуска;
  6. запись воспроизведённого сценария с привязанным к ней кадром.

Какие из них достаточны для двух критериев и что остаётся непроверенным? Прикиньте ответ, прежде чем читать дальше.

Разбор. Первый критерий закрывает пункт 3: настоящая пара прогонов на одном тесте. Diff из пункта 4 объясняет, что изменилось в коде, но прогон он не заменяет - изменение и выполнение это разные вещи. Второй критерий закрывает пункт 6: кадр вместе с записью сценария, где видно начальное состояние и действие. Пункты 1 и 2 не подтверждают ничего: сообщение о готовности не содержит проверяемого подтверждения, а инструкция описывает будущее действие. Пункт 5 показывает число 3 и на этом останавливается, начисление по нему не установить. Ну и сохранение результата в лидерборде остаётся непроверенным даже при всех шести материалах на столе: сценария, в котором сохранённое значение прочитали обратно, среди них нет.

Собрать такой журнал можно и в сессии. Готовый промпт:

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

Как собрать доказательства с Claude Code

Порядок работы получается такой:

  1. агент связывает каждый критерий с конкретной проверкой: что запустить, на каком состоянии кода, что считать результатом;
  2. выполняет те проверки, которые в этой среде доступны, и показывает команду с исходным выводом;
  3. прикладывает наблюдения: фрагменты вывода, ссылки на полные файлы, описание воспроизведённого сценария;
  4. явно обозначает предел: что осталось незапущенным, чего по имеющимся материалам утверждать нельзя.

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

Совет

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


Техническая справка: git diff, git stash, Node.js test runner, npm test, изображения в Claude Code.