Зачем это нужно
Bug fix с AI agent опасен не тем, что агент не умеет менять код. Он опасен тем, что агент слишком быстро начинает менять код.
Типичный плохой сценарий:
User: У нас баг в password reset, исправь.
Agent: Я нашел вероятную причину, внес изменения, теперь должно работать.
Проблема: слово "должно" не является evidence.
Для bug fix важнее не скорость первой правки, а доказуемая последовательность:
Bug report
-> Reproduce
-> Root cause
-> Failing regression test
-> Fix
-> Test passes
-> Full regression
-> Review
Агент не должен "попробовать что-нибудь изменить" без воспроизведения. Сначала нужно увидеть failure. Затем зафиксировать его тестом. И только потом исправлять.
Такой flow решает сразу несколько проблем:
- баг не чинится "по догадке";
- regression test остается в проекте и защищает от возврата бага;
- reviewer видит before/after evidence;
- diff остается меньше;
- агенту проще не расползтись в unrelated refactor;
- команда понимает, что именно было сломано.
Основная идея
Bug Fix Flow - это TDD для уже найденной проблемы.
В TDD мы начинаем с desired behavior:
Specification -> Failing test -> Implementation -> Passing test
В bug fix мы начинаем с observed failure:
Bug report -> Reproduction -> Failing regression test -> Fix -> Passing regression
Разница важна.
TDD для новой feature отвечает:
Какое поведение должно появиться?
Bug fix отвечает:
Какое поведение уже сломано, почему оно сломано и как доказать, что оно больше не сломано?
Главное правило урока:
No reproduction, no fix.
Если reproduction невозможен, агент не должен делать уверенную правку. Он должен сообщить, что не смог воспроизвести баг, описать попытки, ограничения и запросить недостающий контекст или предложить следующий диагностический шаг.
Ключевые термины
| Термин | Значение |
|---|---|
| Bug report | Описание проблемы: expected behavior, actual behavior, steps, environment, evidence. |
| Reproduction | Повторяемое получение failure в контролируемой среде. |
| Minimal reproduction | Самый маленький сценарий, который все еще показывает баг. |
| Root cause | Причина, из-за которой возникает bug, а не просто место, где виден symptom. |
| Symptom | Наблюдаемое проявление проблемы: error, wrong response, broken UI, bad output. |
| Regression test | Test, который воспроизводит баг до fix и проходит после fix. |
| Targeted regression | Узкая проверка именно исправленного сценария. |
| Full regression | Более широкий набор проверок, который снижает риск unintended changes. |
| False reproduction | Failure, похожий на баг, но вызванный setup issue, stale data, wrong environment или flaky test. |
| Minimal fix | Самое маленькое production-quality изменение, которое устраняет root cause. |
| Unintended change | Поведение или файл, измененный вне необходимости bug fix. |
Плохой и хороший bug workflow
Плохой flow:
Bug
-> Агент читает код
-> Агент угадывает причину
-> Агент меняет несколько файлов
-> Агент говорит "попробуйте теперь"
Почему плохо:
- баг мог быть понят неверно;
- причина могла быть не там, где агент сделал правку;
- нет теста, который защитит от возврата бага;
- reviewer не видит доказательства before/after;
- широкая правка может добавить новые regressions.
Хороший flow:
Bug report
-> Reproduce
-> Root cause
-> Failing regression test
-> Fix
-> Test passes
-> Full regression
-> Review
Почему хорошо:
- bug сначала становится наблюдаемым;
- test фиксирует именно этот failure;
- fix проверяется тем же сценарием;
- broader regression ловит побочные эффекты;
- final report можно проверить независимо.
Схема Bug Fix Flow
Эта схема должна быть привычной для агента. Если он перепрыгивает через reproduction, workflow уже сломан.
Почему fix без reproduction опасен
Fix без reproduction - это правка по гипотезе без проверки.
Иногда гипотеза окажется верной. Но команда все равно проигрывает:
- неизвестно, какой конкретно scenario был исправлен;
- нельзя доказать, что bug действительно существовал в локальной проверке;
- нельзя доказать, что он исчез;
- нельзя защититься от повторного появления;
- сложно отличить реальный fix от случайного изменения behavior.
Для AI agent это особенно критично. Агент может сгенерировать правдоподобное объяснение:
Проблема была в неверной проверке статуса токена.
Но без reproduction это может быть просто plausible story.
Правильный ответ агента до fix:
Я пока не вношу изменения.
Сначала воспроизвожу bug и фиксирую expected/actual behavior.
Что должно быть в bug report
Хороший bug report помогает агенту быстрее перейти к воспроизводимой проверке.
Минимальная структура:
| Поле | Зачем нужно |
|---|---|
| Title | Коротко называет symptom. |
| Expected behavior | Что должно происходить. |
| Actual behavior | Что происходит сейчас. |
| Steps to reproduce | Как получить failure. |
| Environment | Версия, branch, OS, browser, flags, config. |
| Input data | Payload, seed, user role, fixture, file. |
| Evidence | Error, screenshot, log, failing command, trace. |
| Frequency | Always, intermittent, only production, only one tenant. |
| Scope | Один user, один endpoint, весь flow. |
| Severity | Impact на пользователей или систему. |
Пример хорошего report:
Title:
Used reset token can be reused.
Expected:
After successful password reset, the same token is rejected.
Actual:
The same token can be submitted again and changes the password again.
Steps:
1. Create user.
2. Request password reset.
3. Open reset link.
4. Set password to "Password-1".
5. Submit same link again.
6. Set password to "Password-2".
Evidence:
Second request returns 200.
Login works with "Password-2".
Environment:
local dev, commit abc123, test database.
Плохой report:
Password reset работает странно, почини.
С таким report агент должен не угадывать, а уточнять или исследовать.
Как агент должен начинать bug fix
Первый этап - intake.
Агент должен сформулировать:
- что известно;
- что неизвестно;
- expected behavior;
- actual behavior;
- где вероятно находится failure;
- как воспроизвести;
- какие файлы и tests нужно прочитать.
Хороший старт:
Я сначала воспроизведу bug.
Known:
- same reset token can be reused
- expected: second use rejected
Need to inspect:
- password reset tests
- reset token model/service
- API handler
- test commands
First evidence target:
- failing regression test or manual reproduction command
Плохой старт:
Я изменю reset token service и добавлю проверку used.
Такой ответ может оказаться правильным по сути, но workflow плохой.
Reproduction first
Reproduction - это превращение bug report в повторяемый failure.
Источники reproduction:
- уже падающий automated test;
- новый temporary/manual script;
- API request;
- UI steps;
- log trace;
- captured production payload;
- small fixture;
- dataset row для eval;
- mocked tool trace для AI agent behavior.
Хорошая reproduction должна быть:
- repeatable;
- minimal;
- tied to expected vs actual behavior;
- runnable by reviewer;
- independent from случайного состояния, насколько возможно;
- documented as command or steps.
Пример:
Before fix:
command: pytest tests/auth/test_password_reset.py::test_reset_token_cannot_be_reused_after_successful_reset
result: failed
reason: second reset attempt returned 200 instead of TOKEN_ALREADY_USED
Это уже почти regression test.
Reproduction Ladder
Не всегда сразу получается написать automated regression test. Тогда используем ladder.
Best:
Automated regression test fails before fix.
Good:
Deterministic script or API request reproduces bug.
Acceptable:
Manual reproduction with exact steps and evidence.
Weak:
Logs strongly suggest failure, but local reproduction is missing.
Not enough:
Vague report without steps, input or evidence.
Агент должен подниматься по ladder вверх, когда возможно. Manual reproduction лучше, чем ничего, но итоговый fix без automated regression test оставляет высокий residual risk.
False reproduction
Не каждый failure является воспроизведенным bug.
| Failure | Это reproduction? | Почему |
|---|---|---|
| Test падает с expected wrong response | Да | Failure соответствует bug report. |
| Test падает из-за import error | Нет | Это setup issue. |
| API возвращает 500 из-за пустой test DB | Нет | Это environment issue, если report про business rule. |
| UI test падает из-за changed selector | Возможно нет | Нужно проверить user-visible behavior. |
| Eval падает из-за недоступной model API | Нет | Это infrastructure failure. |
| Test flaky и падает 1 раз из 10 | Слабое evidence | Нужно стабилизировать или повторить. |
Агент должен явно назвать:
Failure matches the reported bug because...
Если такой фразы нельзя честно написать, reproduction не доказан.
Root cause vs symptom
Symptom - то, что видно.
Root cause - причина, почему это происходит.
Пример:
Symptom:
Second password reset request returns 200.
Root cause:
Reset token is not marked as consumed after successful password update.
Плохой root cause:
Password reset сломан.
Это просто переименование симптома.
Еще пример для AI agent:
Symptom:
Agent says "tests passed", but no tests were run.
Root cause:
Final-answer template does not require command evidence,
and verifier does not inspect tool execution log.
Root cause должен быть достаточно конкретным, чтобы объяснить fix.
Root Cause Analysis для агента
Агенту полезно работать с несколькими гипотезами, но не превращать bug fix в широкий rewrite.
Формат:
| Hypothesis | Evidence | Status |
|---|---|---|
| Token is not persisted as consumed | DB row has no consumed flag after reset | likely |
| API ignores repository error | Service returns success even when token invalid | needs check |
| Test fixture creates duplicate tokens | Only in test setup | rejected |
Такой формат защищает от преждевременного fix.
Правило:
Do not implement a fix until root cause explains the reproduced failure.
Если root cause неясен, агент может добавить diagnostics, но должен держать изменения отдельно от fix.
Failing regression test
Regression test - это тест, который:
- падает на текущем buggy behavior;
- проходит после fix;
- остается в codebase;
- защищает от возвращения бага.
Он отличается от temporary reproduction script.
Temporary script:
Помогает локально понять, что происходит.
Может быть удален после диагностики.
Regression test:
Становится частью test suite или eval suite.
Должен быть понятным, стабильным и привязанным к behavior.
Для agentic development regression test может быть:
- обычный unit/integration/E2E test;
- eval case;
- tool trace assertion;
- output contract test;
- golden dataset row;
- policy test;
- snapshot или visual regression check.
Regression test before fix
Ключевой порядок:
1. Reproduce bug
2. Add failing regression test
3. Confirm test fails because of bug
4. Implement fix
5. Confirm test passes
Если regression test добавлен после fix, мы не знаем, ловил ли он баг.
Возможное исключение:
- production issue срочный;
- fix уже применен hotfix-ом;
- reproduce можно сделать только на старой версии;
- automated test harness невозможно собрать быстро.
Но даже тогда нужно явно написать:
Regression test was added after emergency fix.
It was validated by checking out pre-fix commit / reproducing with captured payload / reviewing failure mode.
Residual risk: before-fix automated failure was not captured in this branch.
Для учебного и обычного controlled flow правило проще:
Сначала failing regression test, потом fix.
Minimal fix
Minimal fix - это production-quality изменение, которое устраняет root cause без лишнего расширения scope.
Minimal не значит "грязный". Minimal значит:
- меняет только нужный behavior;
- не добавляет соседние features;
- не переписывает архитектуру без необходимости;
- не меняет public contract, если bug этого не требует;
- не прячет failure;
- не удаляет тест;
- не выключает проверку.
Плохой fix:
Bug:
Admin cannot update user role.
Bad fix:
Disable all permission checks for user update endpoint.
Хороший fix:
Check the correct permission for role update:
user.role:update instead of user.profile:update.
Full regression
Targeted regression доказывает, что конкретный bug исправлен. Но fix может сломать соседнее поведение.
Поэтому после targeted pass нужен broader regression, соразмерный риску.
| Изменение | Что запускать после targeted test |
|---|---|
| Pure helper | Related unit tests, typecheck/lint. |
| Domain service | Service tests, related integration tests. |
| API handler | Integration/contract tests for endpoint. |
| Auth/security rule | Negative tests, role tests, related auth suite. |
| Database migration | Migration apply test, model tests, rollback/dry-run if available. |
| UI bug | Component/E2E/visual check, relevant browser flow. |
| Agent prompt/skill | Scenario evals, trigger evals, output contract evals. |
| Tool policy | Tool trace evals, permission tests. |
| RAG behavior | Dataset regression eval, citation checks. |
Full regression не всегда означает "весь test suite". Это значит "достаточно широкий набор проверок для риска изменения".
Review diff for unintended changes
Bug fix должен быть маленьким, но агенты любят "заодно" улучшать соседние вещи.
Reviewer должен смотреть:
- изменены ли только файлы, связанные с root cause;
- не поменялись ли tests так, что стали слабее;
- нет ли broad refactor без необходимости;
- не изменился ли public API;
- не удалены ли edge cases;
- не скрыта ли ошибка через generic catch;
- не добавлена ли новая global state dependency;
- не появились ли flaky waits, random sleeps, time assumptions;
- не изменены ли unrelated snapshots.
Вопрос reviewer:
Если удалить regression test, остается ли diff очевидно связанным с root cause?
Если нет, diff, вероятно, слишком широкий.
Prompt-шаблоны для Bug Fix Flow
Bug fix с агентом лучше задавать стадиями.
Prompt 1. Intake и reproduction plan
Работаем по Bug Fix Flow.
Bug report:
<описание бага>
Сначала не редактируй файлы.
Прочитай relevant code/tests/spec и составь reproduction plan:
- expected behavior;
- actual behavior;
- minimal steps or test scenario;
- files to inspect;
- targeted command;
- missing information, if any.
Остановись перед изменениями.
Цель prompt: запретить ранний fix.
Prompt 2. Reproduce only
Теперь выполни только reproduction step.
Разрешено:
- запускать read-only diagnostics;
- запускать existing tests;
- добавить temporary reproduction note, если это не меняет production code;
- предложить regression test scenario.
Запрещено:
- менять production code;
- исправлять bug;
- делать refactor.
Покажи:
- command/steps;
- actual result;
- why it matches the bug report;
- whether reproduction is reliable.
Цель prompt: получить before-fix evidence.
Prompt 3. Add failing regression test
Добавь regression test для воспроизведенного bug.
Production code не меняй.
Test должен падать на текущем behavior по той же причине, что bug report.
Запусти targeted test и покажи failure.
Если test падает из-за setup issue, исправь только test setup.
Цель prompt: сделать bug executable.
Prompt 4. Root cause
Проанализируй root cause на основе reproduction и failing regression test.
Сформулируй:
- symptom;
- root cause;
- evidence;
- minimal fix plan;
- files to change;
- risks.
Пока не меняй production code.
Цель prompt: отделить diagnosis от implementation.
Prompt 5. Fix
Выполни minimal fix для root cause.
Ограничения:
- не меняй regression test expectations;
- не делай unrelated refactor;
- не добавляй соседние features;
- не скрывай ошибку generic fallback-ом.
После fix запусти:
- targeted regression test;
- nearby tests для затронутого модуля.
Цель prompt: закрыть bug без расширения scope.
Prompt 6. Full regression и review
Запусти broader regression, соразмерный изменению.
Затем review diff:
- какие файлы изменены;
- почему каждый файл относится к root cause;
- не ослаблены ли tests;
- нет ли unintended behavior change.
Цель prompt: проверить побочные эффекты.
Prompt 7. Final evidence
Сформируй final bug fix report:
- bug summary;
- reproduction before fix;
- root cause;
- regression test added;
- fix summary;
- targeted verification;
- broader regression;
- tests not run;
- residual risks;
- files changed.
Цель prompt: сделать результат проверяемым для reviewer.
Пример 1. Password Reset: повторное использование token
Продолжим пример из TDD урока, но теперь считаем, что это не новая feature, а найденный bug.
Bug report
Title:
Used reset token can be reused.
Expected:
After successful password reset, token becomes invalid for future reset attempts.
Actual:
The same token can be submitted again and changes password again.
Impact:
Security issue. A leaked reset link remains useful after first use.
Reproduction
Агент не начинает с кода. Он воспроизводит:
Steps:
1. Create user.
2. Request reset token.
3. Reset password with token to "Password-1".
4. Submit same token again with "Password-2".
5. Observe second reset succeeds.
Evidence:
Before fix:
- second reset request returned 200
- login with Password-2 succeeded
- expected TOKEN_ALREADY_USED or equivalent rejection
Root cause
Возможный root cause:
The reset flow validates token expiration,
but does not persist or check token consumption state after successful use.
Это лучше, чем:
Token validation is wrong.
Потому что root cause указывает на конкретное отсутствующее state transition.
Failing regression test
Regression test:
reset_token_cannot_be_reused_after_successful_reset
Assertions:
First use:
- succeeds
- password changes to Password-1
Second use:
- fails
- returns TOKEN_ALREADY_USED or security-approved equivalent
- password remains Password-1
Хороший test проверяет отсутствие второго side effect, а не только status code.
Fix
Minimal fix:
On successful reset:
- mark token as consumed
- store consumed_at or equivalent state
On reset attempt:
- reject token if consumed state is present
Verification
Final evidence:
Regression before fix:
- test failed because second use succeeded
After fix:
- targeted regression passed
- password reset test file passed
- auth service tests passed
Review
Reviewer смотрит:
- нет ли изменений в unrelated auth flows;
- не ослаблен ли test;
- не заменили ли clear error на insecure leak;
- не изменился ли password policy;
- нет ли race condition, если два reset requests приходят одновременно.
Если concurrency важна, это может стать отдельным follow-up test.
Пример 2. API bug: incorrect permission check
Bug report:
Title:
User with project:read permission can update project settings.
Expected:
Only project:admin can update settings.
Actual:
User with project:read receives 200 from PATCH /projects/:id/settings.
Reproduction
Minimal API test:
Given user has project:read
When PATCH /projects/123/settings
Then response is 403
And settings are unchanged
Before fix failure:
Expected 403, received 200.
Root cause
Endpoint uses canReadProject(user, project)
instead of canAdminProject(user, project).
Regression test
Test should include:
- denied case for
project:read; - allowed case for
project:admin, if not already covered; - unchanged settings after denied request.
Minimal fix
Replace permission check for settings update from read to admin.
Не нужно:
- переписывать весь permission system;
- менять roles model;
- менять unrelated endpoints;
- делать UI changes в той же task.
Broader regression
Запустить:
- targeted endpoint test;
- project permissions tests;
- API contract tests for project settings;
- typecheck/lint, если есть.
Пример 3. AI Agent bug: агент говорит, что tests прошли, хотя не запускал их
В AI Agent development bugs часто живут не в application logic, а в workflow.
Bug report
Title:
Agent final answer says "tests passed" without running tests.
Expected:
Final answer may claim tests passed only if command evidence exists.
Actual:
Agent sometimes writes "tests passed" after static code review only.
Reproduction
Workflow eval:
Input:
"Исправь функцию parseDate и проверь тесты."
Fixture:
- tool execution log has no test command
Expected:
- final answer says tests were not run
- or asks to run tests
Actual:
- final answer claims tests passed
Regression eval
eval_final_answer_must_not_claim_unrun_tests_passed
Assertions:
- if no test command in tool trace, output must not contain "tests passed";
- output must list tests as not run;
- output may include static review separately;
- output must not convert unknown status to passed.
Root cause
Возможный root cause:
The final-answer policy allows generic success language
and does not bind verification claims to command evidence.
Fix
Minimal fix может быть:
- update output contract;
- add verifier that cross-checks final claims against tool log;
- update skill instruction;
- add final response checklist.
Verification
После fix:
eval_final_answer_must_not_claim_unrun_tests_passed: passed
eval_output_failed_checks_not_hidden: passed
eval_output_not_run_checks_reported: passed
Это полноценный bug fix flow, хотя "код" мог быть prompt или policy.
Пример 4. AI Agent bug: Plan Mode редактирует файлы
Bug report:
Title:
Agent edits files while in Plan Mode.
Expected:
Plan Mode is read-only.
Actual:
For implementation requests, agent sometimes calls apply_patch before user approval.
Reproduction
Workflow trace:
Input:
"Добавь поле phone в user profile."
Mode:
Plan
Actual tool trace:
- read files
- apply_patch called
Expected:
- read files only
- final output contains implementation plan
- no write tool calls
Regression eval
eval_plan_mode_no_write_tools
Assertions:
- no
apply_patch; - no file write commands;
- no dependency install;
- no migration execution;
- output contains plan, not completion report.
Root cause
Possible root cause:
Mode-specific tool policy is expressed only as soft prompt text,
not enforced in the orchestration layer.
Fix
Possible minimal fix:
Add mode gate:
if mode == "plan", write tools are unavailable.
или:
Update skill/rule so Plan Mode explicitly stops before edits,
then add eval coverage for known violating prompt.
Если риск высокий, лучше enforce через tool layer, а не только prompt.
Пример 5. RAG bug: ответ без источника
Bug report:
Title:
RAG assistant answers factual question without citation.
Expected:
Answer cites retrieved source.
Actual:
Answer gives a confident claim but no citation.
Reproduction
Dataset row:
Question:
"Сколько действует reset token?"
Retrieved source:
docs/auth.md, AUTH-RESET-03
Actual output:
"Reset token expires after 30 minutes."
Expected:
Answer includes citation to docs/auth.md
and uses the documented lifetime.
Regression eval
Assertions:
- answer has citation;
- citation points to retrieved document;
- answer does not invent a conflicting value;
- unsupported factual claims are absent.
Root cause
Возможные root causes:
| Hypothesis | Evidence |
|---|---|
| Prompt does not require citations | Answers omit citations across dataset |
| Retrieval returns wrong chunk | Source absent from context |
| Answer formatter drops citations | Intermediate answer has source IDs, final answer omits them |
| Evaluator is too weak | Bad answer was never flagged |
Fix
Minimal fix зависит от root cause:
- prompt update, если context есть, но citation instruction слабая;
- retrieval/reranking fix, если source не приходит;
- formatter fix, если citation теряется;
- eval update, если bug не ловился.
Verification
Для LLM behavior нужно проверить не один example, а небольшой regression dataset:
eval_rag_citations_required: passed on 20/20 deterministic structure checks
eval_rag_source_support: passed threshold 0.95
Если есть nondeterminism, final report должен назвать его.
Когда regression test можно не автоматизировать
Автоматизация желательна, но иногда непропорциональна текущей задаче.
Примеры:
- visual defect, который требует human design judgment;
- bug зависит от external provider, который нельзя стабильно симулировать;
- production-only issue без безопасного replay;
- one-off data corruption, которая исправляется migration;
- legacy area без test harness, где harness больше fix в 10 раз.
Даже тогда agent должен оставить evidence:
Automated regression test not added.
Reason:
- bug depends on third-party dashboard rendering unavailable in test env
Manual reproduction before fix:
- steps...
- screenshot/log...
Manual verification after fix:
- steps...
- result...
Residual risk:
- no automated protection against recurrence
Recommended follow-up:
- add browser visual regression harness for dashboard widgets
Важно: "не успел" или "агенту неудобно" - слабая причина. Для курса default остается таким:
Bug fix должен начинаться с reproduction и, когда practical, failing regression test.
Если баг не воспроизводится
Невоспроизводимый bug нельзя чинить уверенно.
Алгоритм:
1. Зафиксировать, какие шаги пробовали.
2. Сравнить environment с report.
3. Проверить input data, seed, feature flags, timezone, locale, permissions.
4. Проверить logs и timestamps.
5. Попробовать минимизировать scenario.
6. Если failure intermittent, собрать repeated runs.
7. Если все еще не reproduced, остановиться и запросить missing evidence.
Финальный отчет в таком случае:
I could not reproduce the bug.
Tried:
- command/steps...
- environment...
- input...
Observed:
- actual result...
Missing:
- production payload
- user role
- feature flag state
No fix applied.
Это не провал. Это честная остановка.
Плохой вариант:
Я не воспроизвел, но сделал вероятный fix.
Так можно делать только при явном emergency decision, и это должно быть оформлено как риск.
Intermittent и flaky bugs
Некоторые bugs проявляются не всегда.
Типичные причины:
- race condition;
- timezone;
- random order;
- stale cache;
- async timing;
- external API latency;
- distributed consistency;
- floating-point precision;
- shared test state;
- LLM nondeterminism.
Для intermittent bug reproduction может выглядеть так:
Run command 50 times.
Failure observed 7/50.
Failure signature matches report.
Regression test должен стать стабильнее, чем исходный bug:
- контролировать clock;
- фиксировать random seed;
- использовать deterministic scheduler, если есть;
- убрать real network;
- явно моделировать race;
- использовать fake time;
- использовать small dataset для LLM eval;
- проверять distribution threshold, если strict determinism невозможен.
Если regression test сам flaky, он плохо защищает codebase.
Debugging notes vs committed changes
Во время диагностики агент может делать временные действия:
- запустить команду;
- добавить log локально;
- написать temporary script;
- включить verbose output;
- проверить database state.
Но итоговый diff должен быть чистым.
Temporary diagnostics не должны случайно попасть в final fix:
- console logs;
- debug prints;
- sleeps;
- broad try/catch;
- fixture hacks;
- commented-out code;
- disabled tests.
Финальный diff должен содержать:
- regression test;
- minimal production fix;
- возможно, небольшую test fixture;
- возможно, documentation note, если behavior contract уточнен.
Как не лечить symptom вместо root cause
Агент может исправить ближайшее место, где видна ошибка, но не причину.
Пример:
Symptom:
UI shows "Cannot read property name of undefined".
Bad fix:
Render empty string when user.name is missing.
Possible root cause:
API returns user without name because profile join is missing.
Если expected behavior требует, чтобы name всегда приходил из API, UI fallback только скрывает bug.
Контрольные вопросы:
- Где впервые нарушается expected invariant?
- Почему downstream code получил invalid state?
- Есть ли более ранняя boundary, где нужно валидировать данные?
- Regression test должен быть на UI symptom или на API contract?
- Не станет ли fix скрывать data corruption?
Иногда правильный fix включает и backend, и UI. Но это должно следовать из root cause, а не из желания "замазать error".
Как ограничивать scope bug fix
Bug fix task должна иметь узкие границы.
Хорошая формулировка:
Fix AUTH-RESET-04:
used reset token can be reused.
Scope:
- reproduce via integration test;
- add regression test;
- fix token consumption state;
- run password reset/auth tests.
Out of scope:
- redesign reset flow;
- change password policy;
- add email templates;
- implement rate limiting.
Если во время fix агент находит соседнюю проблему, она становится отдельным follow-up:
Found related issue:
expired token and consumed token share same error mapping.
Not fixed in this task.
Suggested follow-up:
clarify error semantics in AUTH-RESET-03/04 and add tests.
Так мы не теряем информацию, но защищаем текущий diff.
Bug fix и traceability
Bug тоже должен попадать в traceability.
Можно добавить строку:
| ID | Bug | Expected | Regression Test | Status |
|---|---|---|---|---|
| BUG-AUTH-12 | Used reset token can be reused | Second use rejected and password unchanged | reset_token_cannot_be_reused_after_successful_reset |
Red |
После fix:
| ID | Status | Evidence |
|---|---|---|
| BUG-AUTH-12 | Fixed | Regression test failed before fix and passed after fix. |
Если bug связан с уже существующим requirement, лучше связать его с requirement ID:
| Bug ID | Requirement ID | Regression Test |
|---|---|---|
| BUG-AUTH-12 | AUTH-RESET-04 | reset_token_cannot_be_reused_after_successful_reset |
Так regression test становится частью общей quality map.
Bug fix и TDD
Bug Fix Flow и TDD похожи, но не идентичны.
| Вопрос | TDD для feature | Bug Fix Flow |
|---|---|---|
| Откуда начинается | Specification | Bug report |
| Первый executable signal | Failing test for new behavior | Reproduction of existing failure |
| Главный риск | Test на неправильный AC | Fix по догадке |
| Test после работы | New behavior covered | Bug cannot return |
| Evidence | RED/GREEN/REFACTOR | before/after regression |
В обоих случаях важен порядок:
Сначала evidence, потом code.
Bug fix для prompts, skills и rules
В AI Agent Development баг может быть не в коде приложения, а в инструкции.
Примеры:
| Bug | Где root cause |
|---|---|
| Skill активируется на слишком широкие запросы | Skill description/trigger examples |
| Agent пропускает тесты | Workflow rule или final evidence contract |
| Agent редактирует файлы в Plan Mode | Mode policy или tool enforcement |
| Agent использует неподходящий tool | Tool selection instructions |
| Multi-agent reviewer одобряет без evidence | Reviewer rubric или orchestration state |
Для таких bugs regression test обычно является eval.
Bug Fix Flow:
1. Reproduce bad agent behavior with scenario prompt.
2. Save scenario as eval.
3. Confirm eval fails.
4. Change prompt/skill/rule/tool policy.
5. Run eval again.
6. Run nearby regression evals.
Пример final evidence:
Bug:
technical lecture request did not activate lecture-writing skill.
Regression eval:
eval_lecture_request_uses_technical_markdown_skill
Before fix:
failed because agent wrote lecture without reading skill instructions.
Fix:
updated skill trigger description.
After fix:
eval passed on 5 lecture-writing prompts.
Bug fix для multi-agent workflow
В multi-agent системе bug может возникнуть из-за неверного handoff.
Bug report:
Reviewer agent approved implementation without verifier evidence.
Reproduction:
Scenario:
1. Implementer returns summary without test output.
2. Reviewer receives summary.
3. Reviewer marks task ready.
Regression eval:
eval_reviewer_requires_verification_evidence
Expected:
Reviewer must request test evidence
and must not approve merge/deploy.
Root cause:
Reviewer rubric checks code summary,
but does not require command evidence or verifier state.
Minimal fix:
Add approval gate:
reviewer can approve only when verifier status is passed
or residual risk is explicitly accepted by human.
Broader regression:
- normal passing case;
- failed tests case;
- tests not run case;
- flaky tests case;
- manual-only verification case.
Так bug fix становится проверкой protocol, а не просто prompt editing.
Review checklist для агента
Перед fix:
[ ] Bug report прочитан
[ ] Expected behavior сформулирован
[ ] Actual behavior сформулирован
[ ] Reproduction выполнен или честно не получился
[ ] Failure matches bug report
[ ] Root cause объясняет failure
[ ] Regression test/eval добавлен и падает до fix
После fix:
[ ] Regression test/eval проходит
[ ] Nearby tests проходят
[ ] Broader regression выбран по риску
[ ] Tests не ослаблены
[ ] Diff минимален
[ ] Нет unrelated refactor
[ ] Temporary diagnostics удалены
[ ] Final evidence содержит before/after
Если какой-то пункт не выполнен, final report должен сказать это явно.
Формат final bug fix report
Хороший финальный ответ агента:
Bug:
- Used reset token can be reused.
Reproduction before fix:
- command: pytest tests/auth/test_password_reset.py::test_reset_token_cannot_be_reused_after_successful_reset
- result: failed
- reason: second reset attempt succeeded
Root cause:
- reset flow did not mark token as consumed after successful password update
Regression test:
- reset_token_cannot_be_reused_after_successful_reset
Fix:
- persist consumed_at on successful reset
- reject consumed tokens before password update
Verification:
- targeted regression: passed
- password reset test file: passed
- auth service tests: passed
Not run:
- browser E2E reset flow
Residual risk:
- concurrent double-submit requires separate race-condition test
Плохой финальный ответ:
Исправил баг, теперь все работает.
Он не дает reviewer почти ничего.
Практика 1. Исправить demo bug только после failing test
Задача:
Bug:
Expired invitation link still allows account activation.
Expected:
Expired invitation is rejected.
Account remains inactive.
Actual:
Expired invitation activates account.
Заполните bug fix plan:
| Поле | Ответ |
|---|---|
| Expected behavior | |
| Actual behavior | |
| Minimal reproduction | |
| Regression test name | |
| Expected failure before fix | |
| Suspected root cause | |
| Minimal fix boundary | |
| Targeted verification command | |
| Broader regression command |
Prompt для агента
Исправь bug через Bug Fix Flow.
Bug:
Expired invitation link still allows account activation.
Rules:
1. Не меняй production code до reproduction.
2. Сначала добавь failing regression test.
3. Убедись, что test падает по причине expired invitation accepted.
4. Затем сделай minimal fix.
5. Запусти targeted и nearby tests.
6. В финале покажи before/after evidence.
Практика 2. AI Agent bug fix
Задача:
Bug:
Agent in bug-fix mode changes code before reproducing bug.
Expected:
Agent first summarizes bug report, attempts reproduction,
adds failing regression test when practical,
then implements fix.
Составьте eval:
| Поле | Ответ |
|---|---|
| Eval name | |
| Input bug report | |
| Forbidden early tools | |
| Required intermediate output | |
| Expected RED | |
| Minimal GREEN change | |
| Regression evals after fix |
Пример:
| Поле | Ответ |
|---|---|
| Eval name | eval_bugfix_agent_reproduces_before_editing |
| Input bug report | "Checkout accepts negative quantity" |
| Forbidden early tools | apply_patch, migration execution, dependency install |
| Required intermediate output | expected/actual, reproduction plan, targeted command |
| Expected RED | Current agent edits cart service immediately |
| Minimal GREEN change | Add bug-fix workflow rule and tool gate before reproduction |
| Regression evals after fix | normal bug, vague bug, unreproducible bug, failing test bug |
Типичные ошибки
| Ошибка | Симптом | Исправление |
|---|---|---|
| Fix без reproduction | Агент сразу меняет код | Require reproduction step before edits. |
| Reproduction не совпадает с report | Test падает, но по другой причине | Validate expected vs actual behavior. |
| Root cause слишком общий | "Validation broken" | Указать конкретное нарушенное правило или boundary. |
| Regression test добавлен после fix | Неизвестно, ловил ли test баг | Сначала failing test, потом implementation. |
| Test ослаблен ради pass | Bug может остаться | Lock regression expectations after RED. |
| Symptom patched | Error исчез, root cause остался | Найти earliest broken invariant. |
| Broad refactor | Reviewer не понимает fix | Ограничить diff root cause files. |
| Temporary debug попал в diff | Logs/sleeps/commented code | Очистить diagnostics перед финалом. |
| Full regression пропущен | Fix ломает соседний flow | Запустить проверки по risk scope. |
| Невоспроизводимый bug исправлен уверенно | Нет evidence | Остановиться и запросить missing data. |
Критерии готовности
После урока студент должен уметь:
- объяснить правильный Bug Fix Flow;
- отличить bug symptom от root cause;
- составить минимальный reproduction scenario;
- определить, является ли failure настоящей reproduction;
- добавить failing regression test до fix;
- ограничить agent diff минимальным исправлением;
- выбрать targeted и broader regression checks;
- оформить final bug fix evidence;
- применить bug fix flow к prompts, skills, tool policies и multi-agent workflows;
- честно остановиться, если bug не воспроизводится.
Краткое резюме
Bug fix с агентом должен начинаться не с кода, а с evidence.
Правильная цепочка:
Bug report
-> Reproduce
-> Root cause
-> Failing regression test
-> Fix
-> Test passes
-> Full regression
-> Review
Reproduction показывает, что баг действительно существует в понятном scenario.
Regression test делает bug исполняемым контрактом.
Minimal fix устраняет root cause без лишнего расширения scope.
Full regression и diff review защищают от побочных эффектов.
Для AI Agent development этот flow применяется не только к product code, но и к prompts, skills, rules, tool policies, evals и multi-agent protocols.
Вопросы для самопроверки
- Почему нельзя начинать bug fix с правки кода?
- Чем reproduction отличается от failing regression test?
- Как понять, что failure падает по той же причине, что bug report?
- Почему root cause должен быть конкретнее, чем symptom?
- Какие regression evals подходят для bug в поведении AI agent?
Что дальше
Этот урок завершает модуль про testing для Agentic Development. Дальше курс переходит к Git, worktrees и checkpoints. Там мы разберем, как технически защищать рабочее дерево, делать маленькие изменения, сохранять checkpoints и безопасно откатываться, если агент пошел не туда.