1. Сначала — честный красный
Разговоры, картинки и одна пойманная ловушка — это всё было только что. На руках у Тёмы уже всё что надо: ТЗ с разведёнными четырьмя графами, лог до строки 9, понятая зелёная ловушка и правило честного теста. Сам баг тоже починен ещё днём — код правильный, табло показывает три. Не хватает одного, самого главного: честного доказательства. Потому что проверка у него до сих пор та самая — Санина пустышка с закомментированным нутром. Код починён, а доказать это нечем.
Вот с этого Тёма и начинает — с проверки. И первое, что он пишет Сане, раньше бы и в голову не пришло:
— Сань, ту проверку, что ты закомментировал, — верни к жизни. Раскомментируй if, пусть снова сравнивает счёт с тройкой и орёт, если не сходится. Только зеленить раньше времени не смей — сначала докажи мне, что она вообще умеет краснеть.
Не «лишь бы зелёное», как просил бы пару недель назад. А наоборот: пусть проверка сперва честно покажет красный на сломанном. Тест-то у него был с самого утра, тот самый «три в ряд должны дать три» — его не писать надо заново, а воскресить: Саня же его не выкинул, а усыпил двумя палочками //.
Саня возвращает if на место — проверка снова живая и зубастая. И тут же встаёт тонкость, которую легко прозевать. Проверку надо держать отдельно от фикса: сохранить её в гите (закоммитить), чтобы она не уехала в карман вместе с правкой счёта. Иначе stash заберёт и фикс, и саму проверку — и проверять станет нечем. Тёма просит Саню помочь:
— Сохрани проверку в гит отдельным коммитом. А потом убери в карман только правку счёта, src/bonus-game/score.js — вернём баг и посмотрим, покраснеет ли.
Саня коммитит тест и прячет только фикс:
● git commit -m "restore score test" # честная проверка сохранена отдельно
● git stash push -- src/bonus-game/score.js # в карман уходит ТОЛЬКО фикс счёта; тест остаётся
Тёма просит прогнать проверку:
FAIL score.test.js # 3 в ряд → ожидалось 3, получено 30
Красное. FAIL.
— О, — говорит Тёма вслух и ловит себя на том, что улыбается красному тесту. Дожили: пару недель назад это была лампа «у тебя не работает», провал, повод поморщиться. А сейчас он смотрит на этот FAIL почти с нежностью. Потому что красный тут — хорошая новость: значит, проверка наконец-то смотрит ровно туда, куда нужно. Она увидела баг. Она умеет краснеть.
Он секунду держит этот красный на экране. Утренняя пустышка была зелёной и слепой. Эта — красная и зрячая. И из них двоих верить можно только зрячей.
2. Честное зелёное
Красный доказан. Теперь — вернуть фикс. Чинить заново ничего не надо: правильный код Саня сложил ещё днём, он просто ждёт своей минуты в кармане. Тёма просит достать его обратно и прогнать тот самый тест, который только что честно покраснел — не «там счёт врёт», а проверку, которая прямо завязана на баг.
● git stash pop # достать готовый фикс из кармана — вернуть на место
Секунда. Идет прогон тестов. Тёма ловит себя на том, что не дышит — утром его это самое зелёное уже один раз обмануло, и теперь он ему не верит вперёд, ждёт. Сейчас либо вывалит красным, либо…
PASS score.test.js # 3 в ряд → 3 очка
Зелёное.
И в этот раз Тёма смотрит на PASS без утреннего доверия — он теперь знает цену зелёному. Но это зелёное другое, и он проговаривает разницу вслух:
— А вот тебе я верю. Полчаса назад ты на этом же баге честно краснел, я сам видел. А теперь позеленел на фиксе. Краснел на сломанном — зеленеешь на починенном. Тебя не подделать: подделка краснеть не умеет.
Но тесту на слово он уже не верит — учёный. Открывает bonus-game, гоняет живьём, собирает три в ряд.
На табло — честные три. Не тридцать.
Тёма откидывается на спинку и выдыхает. Не тот восторг, что от игр раньше, — что-то спокойнее и тяжелее. Зелёное на экране теперь значит ровно то, что должно. Лампа горит зелёным, и за ней правда нет дыма.
— Я тебе не поверил, — говорит он PASS-у на экране почти весело. — Я тебя доказал.
3. Второй канал — скриншот через зрячую модель
Тест доказал своё — честно покраснел на баге, позеленел на фиксе. Но Тёма помнит, что Лёха обещал ещё один канал, глазами. И теперь он сам его прогоняет — то, что днём было теорией про «надеть очки».
Снимает скриншот экрана счёта уже после фикса — score-after.png, где на табло честные три. И переключается на видящую модель:
/model # выбрать видящую (vision) модель — «надеть очки»
Потом подаёт картинку в сессию и просит подтвердить:
Вот скриншот экрана счёта @screenshots/score-after.png — подтверди, что счёт теперь правильный.
Зрячая модель смотрит на кадр и отвечает по делу: за три в ряд — три очка, не тридцать. Не пересказ Тёмы, не «я проверил» — сам агент описал, что на картинке. Значит, увидел.
— О, так вот почему тогда на лендинге скриншот отлично отработал, — доходит до Тёмы. — Среда сама подсунула зрячую модель, а я и не заметил. А теперь я переключил руками — и вижу всю кухню.
Он возвращает рабочую модель — /model, "очки" больше не нужны — и подводит итог Сане:
— Смотри, что вышло. На фикс у меня теперь две улики: тест, который умеет краснеть, и картинка, которую видела сама модель. Одну подделать — вторая не сойдётся. Разом обе не подделаешь.
4. EVIDENCE_LOG — улика, которую собрал сам
Когда баг починен и доказан, Лёха пишет одну фразу, по-дисциплинарному скупо после тяжёлых дней:
— То, что ты сейчас собрал, называется EVIDENCE_LOG. Доказательный пакет. Не «готово», а цепочка фактов, которой починка подтверждает себя сама.
Больше он ничего не объясняет — замолкает. И срабатывает привычка Тёмы вытягивать вопросами. Он узнаёт форму не на пустом месте: раньше он уже собирал облегчённую карточку-улику под один горящий симптом — EVIDENCE_LOG-lite. Это был зародыш.
— А чем эта полная штука отличается от той lite-карточки? — спрашивает Тёма.
— Lite фиксировала только улику: «вот сломалось». А полный должен ещё доказать, что улика исчезла именно от починки, а не сама собой. Вся дуга — от красного на сломанном до зелёного на фиксе.
Тёма переспрашивает у Сани, что обязано лежать внутри, чтоб пакету можно было верить, — и так, по вопросу за раз, вытягивает структуру. Собирает её сам, поле за полем, из того, что прожил за день:
# EVIDENCE_LOG — баг счёта в bonus-game
1. СИМПТОМ: 3 в ряд = 30 очков вместо 3
2. ЛОГ-УЛИКА: calcScore (src/bonus-game/score.js:9) — POINTS_PER_MATCH=10 вместо 1
3. ПАДЕНИЕ НА СЛОМАННОМ: тест красный на баге (иначе веры ему ноль)
4. ПОЧИНКА: POINTS_PER_MATCH с 10 на 1 в calcScore
5. ЧЕСТНОЕ ЗЕЛЁНОЕ: тот же тест зелёный на фиксе
6. СКРИНШОТ: score-after.png — зрячая модель подтвердила честные 3 на табло
Тёма смотрит на эти шесть строк и понимает, почему такой пакет нельзя подделать одним фейковым зелёным отчетом. Каждый пункт перепроверяем руками. Зелёное здесь стоит не само по себе — оно зажато между красным-до и скриншотом-после. Это не «я всё проверил, работает». Это улика, которую можно открыть и пройти по шагам.
5. Проверка — это тоже ремесло
Олег возвращается и тормозит у экрана. Обычно он на тёминых забавах не задерживается — насмотрелся на мальчиков, которые написали красивую игрушку и решили, что стали инженерами. Тёма у него до сих пор шёл по той же графе.
— Это что у тебя, — кивает Олег на экран. Ждёт увидеть вау-демку.
А там не демка. Там EVIDENCE_LOG: красное на сломанном, причина в логе, честное зелёное после фикса, скриншот. Олег пробегает шесть строк глазами. Раз, второй. Хмыкает — и хмык совсем не тот, что обычно.
— Погоди. Так ты не просто инструмент дернул. — Он смотрит на Тёму без привычной кислой мины. — Ты ложный тест проверкой поймал. Наш человек. Красавчик.
Подмигивает и уходит, не дожидаясь ответа. Но Тёма всё равно чувствует короткое тепло — старовер, который в «магию ИИ» не верит ни на грош, только что разглядел в нём ремесло. А ремесло Олег уважает.
И вдруг главное за весь день складывается у него само.
— Слушай, — пишет он Лёхе. — А ведь меня сегодня спасла не крутая модель. Саня сильный — а ловушку всё равно подсунул. Спас порядок. Который не дал зелёной лампочке проскочить без проверки.
— Запиши и повесь на стенку, — отвечает Лёха. — Хорошая модель не спасает от плохого процесса. А хороший процесс ловит даже красивую ложь.
Тёма перечитывает свой EVIDENCE_LOG. Скучная обуза, которую он неделями таскал мёртвым грузом, сегодня первый раз сработала — и не крутая модель, а вот эти шесть занудных строк.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ