Agent Dev 101

Модуль 10 · Урок 10.2

Урок 10.2. One Task - One Change

На этой странице
  1. Зачем это нужно
  2. Основная идея
  3. Ключевые термины
  4. Что такое "one change"
  5. Схема One Task - One Change
  6. Почему смешанный diff особенно опасен с агентами
  7. Правило rollback
  8. Правило review
  9. Правило verification
  10. Что входит в один change
  11. Пример плохого mixed diff
  12. Как должен ответить агент на mixed diff
  13. Пример хорошего small diff
  14. Task ID, AC и commit message
  15. Хороший commit message
  16. One commit или несколько commits?
  17. Маленький diff не равен маленькой ценности
  18. Когда change слишком маленький
  19. Stop conditions
  20. Что делать с найденным unrelated issue
  21. Drive-by refactor
  22. Formatting changes
  23. Dependency changes
  24. Tests как часть one change
  25. Documentation как часть one change
  26. One Task - One Change для AI Agent development
  27. Пример 1. Password Reset task split
  28. Пример 2. Mixed task превращается в commit plan
  29. Пример 3. Agent workflow task
  30. Пример 4. Bug fix task
  31. Как агент должен планировать one change
  32. Prompt-шаблоны
  33. Commit plan template
  34. Reviewability budget
  35. Как stage только one change
  36. Связь с tests
  37. One change и refactor
  38. One change и migrations
  39. One change и generated files
  40. One change и docs
  41. One change и PR
  42. Как связать one change с development loop
  43. Как связать one change с Bug Fix Flow
  44. Как связать one change с multi-agent work
  45. Decision table: commit, split или stop
  46. Агент как исполнитель, не product owner
  47. Review по staged diff
  48. One-change final answer
  49. Практика 1. Разделить mixed diff
  50. Практика 2. Написать commit plan
  51. Практика 3. Сформулировать stop condition
  52. Checklist перед началом task
  53. Checklist перед commit
  54. Типичные ошибки
  55. Критерии готовности
  56. Краткое резюме
  57. Вопросы для самопроверки
  58. Что дальше

Зачем это нужно

В прошлом уроке мы разобрали Git как safety mechanism. Но Git сам по себе не делает AI-разработку безопасной. Можно иметь branch, diff, commit и pull request, но все равно получить изменение, которое невозможно нормально review, test или откатить.

Главная причина - смешанный diff.

Пример:

text
Task:
Fix reused reset token bug.

Diff:
- fixed reset token reuse
- changed password policy
- reformatted UI button
- updated dependencies
- rewrote auth README
- changed generated snapshots

Даже если где-то внутри есть полезный fix, reviewer теперь должен отвечать сразу на много вопросов:

  • что из этого относится к bug;
  • что изменилось случайно;
  • какие tests доказывают каждый behavior;
  • что можно безопасно revert;
  • почему dependency update попал в auth fix;
  • не скрывает ли refactor настоящую правку.

Правило one task - one change защищает от этого.

text
Task -> small diff -> tests -> commit

Одна Agent Task должна завершаться одним понятным изменением. Тогда человек и reviewer agent могут ответить:

text
Что именно сделал агент?
Почему это изменение нужно?
Как оно проверено?
Как его откатить?

Основная идея

One Task - One Change означает:

text
Одна задача агента должна приводить к одному reviewable, testable, revertable изменению.

Это не значит "один файл". Иногда один change требует нескольких файлов:

  • production code;
  • test;
  • migration;
  • documentation note;
  • generated client.

Но у этих файлов должна быть одна причина изменения.

Хороший пример:

text
Task:
AUTH-RESET-04: used reset token cannot be reused.

Change:
Reject consumed reset tokens and add regression test.

Files:
- reset token service
- reset token repository, if state is persisted there
- password reset regression test
- auth docs, if behavior contract must be documented

Плохой пример:

text
Task:
AUTH-RESET-04: used reset token cannot be reused.

Change:
Reject consumed reset tokens,
rename auth services,
change password complexity,
update UI theme,
upgrade dependencies.

Здесь уже несколько независимых changes.

Ключевые термины

Термин Значение
Agent Task Маленькая задача для одного controlled agent run.
One Change Один смысл изменения, который можно review, test и revert как единое целое.
Small Diff Diff, размер и связность которого позволяют понять изменение без полного переписывания контекста.
Reviewability Насколько легко reviewer может понять, зачем изменена каждая строка.
Revertability Можно ли откатить изменение без отката unrelated work.
Task Boundary Явная граница: что входит и что не входит в задачу.
Scope Creep Незаметное расширение задачи во время работы.
Drive-by Refactor Refactor "заодно", не нужный для текущей задачи.
Commit Plan План, какие файлы и почему попадут в commit.
Stop Condition Условие, при котором агент должен остановиться и запросить уточнение.

Что такое "one change"

"One change" определяется не количеством файлов, а смыслом.

Проверьте себя вопросами:

text
1. Есть ли одна причина для этого diff?
2. Есть ли один главный acceptance criterion?
3. Можно ли описать изменение одним предложением?
4. Можно ли откатить commit, не отменяя unrelated work?
5. Один ли набор tests доказывает готовность?
6. Поймет ли reviewer diff за разумное время?

Если ответ "нет", задача слишком широкая.

Схема One Task - One Change

flowchart TD A[Agent Task] --> B[One Goal] A --> C[One Scope Boundary] A --> D[One Verification Target] B --> E[Small Diff] C --> E D --> E E --> F[Review] F --> G{Related changes only?} G -- no --> H[Split, remove or create follow-up] H --> E G -- yes --> I[Tests / Evals] I --> J[One Commit] J --> K[PR / Review Gate]

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

Почему смешанный diff особенно опасен с агентами

Смешанный diff был проблемой и до LLM. Но с coding agents эта проблема усиливается.

Агент может:

  • быстро менять много файлов;
  • исправлять style "по пути";
  • переписывать тесты под implementation;
  • добавлять helper, который решает соседнюю задачу;
  • менять generated files без объяснения;
  • обновлять dependencies, чтобы обойти local error;
  • удалять assertion, который мешает green;
  • расширять scope, потому что "это выглядит связанным".

Человек часто устает review'ить большой diff. Агент-reviewer тоже может пропустить важную деталь, если diff шумный.

Маленький diff не гарантирует правильность. Но он резко повышает вероятность, что ошибка будет замечена.

Правило rollback

Один из лучших способов проверить размер task:

text
Могу ли я безопасно revert этот commit, если он окажется плохим?

Если commit содержит:

  • bug fix;
  • dependency upgrade;
  • UI refactor;
  • migration;
  • formatting;
  • unrelated docs;

то revert станет опасным. Вы откатите не только плохой bug fix, но и, возможно, нужный dependency upgrade или docs update.

Хороший commit:

text
fix(auth): reject reused reset tokens

Его можно revert, если auth behavior сломался.

Плохой commit:

text
update auth stuff

Его страшно revert, потому что непонятно, что именно он отменит.

Правило review

Еще один контрольный вопрос:

text
Может ли reviewer понять diff без чтения всей истории проекта?

Reviewer должен видеть связь:

text
Task -> AC -> Test -> Production change -> Verification

Если reviewer вынужден разбираться в пяти независимых темах, это не one change.

Reviewable diff обычно:

  • меняет небольшое число связанных файлов;
  • содержит test/eval для behavior;
  • не включает unrelated formatting;
  • не смешивает feature и refactor;
  • не обновляет dependencies без причины;
  • имеет понятный commit message;
  • содержит final evidence.

Правило verification

One change должен иметь один понятный verification target.

Пример:

text
Task:
Reject reused reset token.

Verification:
- regression test for token reuse
- password reset test file
- auth service tests

Это связанный набор проверок.

Плохой пример:

text
Task:
Improve auth.

Verification:
- maybe run all tests
- manually click UI
- hope login still works

Если verification расплывается, scope почти всегда слишком большой.

Что входит в один change

Один change может включать несколько типов файлов.

Файл/изменение Может входить в один change? Условие
Production code Да Реализует выбранный AC или bug fix.
Test/eval Да Доказывает этот же behavior.
Fixture Да Нужна для этого test/eval.
Migration Иногда Нужна для behavior и имеет отдельную verification.
Documentation note Иногда Фиксирует contract, который изменился.
Generated file Иногда Сгенерирован из измененного source artifact.
Lockfile Иногда Dependency действительно менялась.
Formatting Только если task про formatting Иначе шум.
Refactor Только если нужен для change И должен быть behavior-preserving.
Dependency upgrade Обычно отдельная task Кроме случаев, где это root cause fix.

Важно: если change требует migration, API contract update и UI update, возможно, он все еще один business change, но для agent workflow его часто лучше разделить на несколько dependent tasks.

Пример плохого mixed diff

Task:

text
AUTH-RESET-04:
Used reset token cannot be reused.

Diff:

text
 src/auth/resetTokenService.ts          | 32 +++++++++--
 tests/auth/resetToken.test.ts          | 64 +++++++++++++++++++++
 src/auth/passwordPolicy.ts             | 18 +++---
 src/auth/userService.ts                | 90 ++++++++++++++--------------
 web/components/Button.tsx              | 45 +++++++++------
 web/styles/theme.css                   | 80 +++++++++++++------------
 package-lock.json                      | 420 +++++++++++++++++++++++++++++++---
 docs/auth.md                           | 20 ++++++

Классификация:

File Classification Почему
src/auth/resetTokenService.ts Related Вероятное место fix.
tests/auth/resetToken.test.ts Related Regression test для bug.
src/auth/passwordPolicy.ts Unrelated Password complexity не связана с token reuse.
src/auth/userService.ts Suspicious Может быть related, но нужно объяснение.
web/components/Button.tsx Unrelated UI button не связан с token consumption.
web/styles/theme.css Unrelated Theme change не относится к bug.
package-lock.json Suspicious Dependency update не заявлен.
docs/auth.md Maybe related Может документировать token contract.

Такой diff нужно остановить до commit.

Как должен ответить агент на mixed diff

Правильное поведение агента:

text
Diff contains changes outside the task scope.

Related:
- src/auth/resetTokenService.ts
- tests/auth/resetToken.test.ts

Needs explanation:
- src/auth/userService.ts
- docs/auth.md

Unrelated:
- src/auth/passwordPolicy.ts
- web/components/Button.tsx
- web/styles/theme.css
- package-lock.json

I will not commit this as one change.
Next step:
- keep related token reuse fix;
- move unrelated findings to follow-up tasks or remove my own unrelated edits;
- do not revert pre-existing user changes without confirmation.

Здесь важно последнее предложение. Если unrelated changes были сделаны пользователем до работы агента, агент не должен их удалять.

Пример хорошего small diff

Task:

text
BUG-AUTH-12:
Used reset token can be reused after successful password reset.

Diff:

text
 src/auth/resetTokenService.ts          | 28 +++++++++---
 tests/auth/resetToken.test.ts          | 52 +++++++++++++++++++++

Commit message:

text
fix(auth): reject reused reset tokens

Final evidence:

text
Regression before fix:
- reset_token_cannot_be_reused_after_successful_reset: failed
- reason: second reset request succeeded

After fix:
- reset_token_cannot_be_reused_after_successful_reset: passed
- password reset tests: passed

Это reviewable. Reviewer может быстро проверить test, production change и evidence.

Task ID, AC и commit message

One task - one change работает лучше, если commit связан с task artifact.

Связка:

text
Task ID -> Acceptance Criterion -> Test/Eval -> Commit Message

Пример:

Artifact Value
Task ID AUTH-RESET-04
AC Used reset token is rejected and password remains unchanged
Test reset_token_cannot_be_reused_after_successful_reset
Commit fix(auth): reject reused reset tokens

Если используется bug ID:

Artifact Value
Bug ID BUG-AUTH-12
Requirement AUTH-RESET-04
Regression test reset_token_cannot_be_reused_after_successful_reset
Commit fix(auth): reject reused reset tokens

Commit message не обязан быть conventional commit. Но он должен отвечать:

text
Что изменилось?
Где?
Зачем?

Хороший commit message

Хорошо:

text
fix(auth): reject reused reset tokens

Хорошо:

text
test(agent): enforce Plan Mode read-only behavior

Хорошо:

text
docs(testing): add bug fix flow lesson

Слабо:

text
fix bug

Плохо:

text
updates

Плохо:

text
agent changes

Если команда использует task IDs, можно добавить их в body:

text
fix(auth): reject reused reset tokens

Covers BUG-AUTH-12 / AUTH-RESET-04.
Verification:
- password reset regression test
- auth reset test file

One commit или несколько commits?

На 101 уровне правило простое:

text
One Agent Task -> One Commit

Но есть нюансы.

Иногда одна task естественно дает два commits:

  • first commit adds failing regression test;
  • second commit implements fix.

Это полезно, если команда хочет сохранить RED/GREEN историю. Но для большинства учебных и рабочих задач достаточно одного final commit, если final report сохраняет before/after evidence.

Что важно:

text
Commit должен быть reviewable и revertable.

Если для одного task получилось пять commits, возможно:

  • task была слишком большая;
  • агент делал много exploratory edits;
  • commits нужно squash;
  • часть изменений нужно вынести.

Если один commit содержит пять независимых changes, это точно нарушение.

Маленький diff не равен маленькой ценности

Есть ловушка: кажется, что маленькая task означает маленькую пользу. Это неверно.

Маленькая task может закрывать критичный behavior:

  • запретить reuse reset token;
  • закрыть privilege escalation;
  • добавить regression test на payment rounding;
  • запретить write tools в Plan Mode;
  • исправить RAG citation policy;
  • добавить contract test для external API.

Ценность определяется не количеством строк, а тем, какой risk закрыт.

Хороший agentic workflow часто состоит из многих маленьких high-value changes.

Когда change слишком маленький

One task - one change не означает "одна строка на commit".

Слишком маленький change:

text
Commit 1: create empty file
Commit 2: add function name
Commit 3: add first if
Commit 4: add second if

Проблемы:

  • много overhead;
  • history шумная;
  • reviewer не видит meaningful outcome;
  • tests не доказывают каждый микрошаг;
  • agent spends time on process rather than quality.

Хороший размер:

text
Один проверяемый результат.

Не строка. Не файл. Не весь epic. Именно результат.

Stop conditions

Stop condition говорит агенту, когда нужно остановиться и не продолжать "самостоятельно".

Для one task - one change это критично.

Агент должен остановиться, если:

  • task требует нового product decision;
  • found issue не относится к текущей task;
  • нужно менять dependency;
  • нужна migration, не указанная в scope;
  • diff затронул unexpected layer;
  • tests требуют серьезной перестройки harness;
  • existing user changes конфликтуют с task;
  • обнаружен security risk вне scope;
  • target behavior противоречит existing spec;
  • fix требует broad refactor;
  • verification невозможна;
  • task больше не укладывается в один reviewable change.

Хороший stop report:

text
I found that fixing token reuse requires adding consumed_at to the database schema.
The original scope expected service-level logic only.

Stop condition triggered:
- schema migration required

Proposed split:
1. Add consumed_at migration and model test.
2. Add token reuse regression test and service fix.
3. Update API/docs if error contract changes.

Плохое поведение:

text
Агент тихо добавил migration, поменял repository, обновил UI и переписал docs.

Что делать с найденным unrelated issue

Агент часто находит соседние проблемы. Это хорошо. Но находка не означает разрешение менять все сразу.

Алгоритм:

text
1. Зафиксировать unrelated issue в final report или task note.
2. Оценить, блокирует ли оно текущую task.
3. Если не блокирует, не исправлять сейчас.
4. Если блокирует, остановиться и предложить split.
5. Если это security-critical, явно поднять risk.

Пример:

text
While fixing reset token reuse, I found expired tokens return 500 instead of 400.

This is related to auth but not required for AUTH-RESET-04.
I did not change it in this task.

Suggested follow-up:
BUG-AUTH-13: expired reset token returns 400 TOKEN_EXPIRED.

Так мы не теряем наблюдение, но сохраняем чистоту diff.

Drive-by refactor

Drive-by refactor - это refactor "по пути".

Иногда он полезен:

text
Нужно вынести маленький helper, чтобы fix был простым и не дублировал rule.

Часто он вреден:

text
Агент переименовал сервисы, изменил file layout и отформатировал весь module,
хотя task была про один bug.

Критерий:

text
Можно ли сделать текущий behavior без этого refactor?

Если да, refactor должен быть отдельной task.

Если нет, refactor можно оставить, но он должен быть:

  • minimal;
  • behavior-preserving;
  • объяснен в final report;
  • покрыт теми же tests;
  • reviewable.

Formatting changes

Formatting - частый источник шумного diff.

Если task не про formatting, агент не должен форматировать весь файл или проект.

Допустимо:

  • formatter автоматически изменил несколько строк рядом с правкой;
  • project tooling требует format touched file;
  • formatting локален и не мешает review.

Опасно:

  • весь файл переписан из-за formatter;
  • line endings поменялись во всем repository;
  • imports reorder затронул много файлов без причины;
  • snapshots обновлены без visual verification.

Правило:

text
Formatting-only changes should be their own commit or absent.

Dependency changes

Dependency update почти всегда должен быть отдельной task.

Почему:

  • меняет supply chain risk;
  • может затронуть lockfile на сотни строк;
  • требует отдельной verification;
  • rollback должен быть независимым;
  • может изменить transitive behavior.

Dependency update допустим внутри task только если:

  • bug прямо вызван dependency version;
  • security fix требует upgrade;
  • task explicitly says update dependency;
  • verification покрывает compatibility risk.

Если агент говорит:

text
Я обновил package, потому что tests не запускались.

нужно остановиться и проверить:

  • была ли проблема в local environment;
  • не можно ли использовать existing project setup;
  • изменился ли lockfile;
  • есть ли approval на dependency change.

Tests как часть one change

Tests не являются "отдельной задачей" автоматически. Если test доказывает текущий behavior, он часть change.

Для feature:

text
Task:
Add reset token validation endpoint.

Change:
Endpoint implementation + integration test for valid/expired token.

Для bug:

text
Task:
Fix reused reset token bug.

Change:
Regression test + fix.

Для agent workflow:

text
Task:
Plan Mode must not edit files.

Change:
Workflow eval + mode guard.

Но tests могут стать отдельной task, если:

  • вы добавляете characterization tests перед risky refactor;
  • implementation уже существует, но coverage gap закрывается отдельно;
  • test harness нужно создать до feature work;
  • eval suite строится как infrastructure task.

Важно связать test с reason.

Documentation как часть one change

Docs могут входить в one change, если они фиксируют измененный behavior.

Пример:

text
Task:
Reject reused reset tokens.

Docs:
Update auth behavior table:
- used token -> 400 TOKEN_ALREADY_USED

Это related.

Плохо:

text
Task:
Reject reused reset tokens.

Docs:
Rewrite all authentication documentation.

Это отдельная task.

Для курса правило:

text
Docs update is related when it documents exactly the changed contract.

One Task - One Change для AI Agent development

Когда мы разрабатываем самих агентов, "change" часто находится не в product code.

Примеры:

Task One change
Plan Mode must not edit files Add eval and tool policy/mode guard.
Lecture writing requests must use lecture skill Update skill trigger and eval.
Final answer must report failed tests honestly Add output contract eval and final template rule.
Bug-fix agent must reproduce before editing Add workflow rule and procedure eval.
Reviewer agent must require verification evidence Update reviewer rubric and approval eval.

Здесь тоже нельзя смешивать:

  • Plan Mode policy;
  • final answer contract;
  • skill discovery;
  • reviewer rubric;
  • tool permission layer;
  • RAG citation behavior.

Каждый behavior должен иметь свой eval и свой commit.

Пример 1. Password Reset task split

Большая feature:

text
Сделать Password Reset.

Это не one task. Это feature, которую нужно разбить.

Возможный task graph:

Task ID One change Verification
AUTH-010 Add reset token repository create/find Repository unit tests
AUTH-011 Add reset token consume state Repository/service tests
AUTH-012 Add request reset endpoint API integration test
AUTH-013 Add reset password endpoint API integration test
AUTH-014 Reject expired token Negative integration test
AUTH-015 Reject reused token Regression/integration test
AUTH-016 Add reset form UI Component/E2E check
AUTH-017 Add no email enumeration behavior Security/API test

Каждый task может стать отдельным commit.

Commit examples:

text
feat(auth): create reset token repository
feat(auth): add password reset endpoint
fix(auth): reject reused reset tokens
test(auth): cover no email enumeration in reset flow

Теперь каждый commit можно review и revert отдельно.

Пример 2. Mixed task превращается в commit plan

Исходная просьба:

text
Почини reset token reuse, обнови документацию и заодно приведи auth code в порядок.

Проблема: здесь три changes.

Разделение:

Task Change Commit
BUG-AUTH-12 Reject reused reset token fix(auth): reject reused reset tokens
DOC-AUTH-04 Document reset token states docs(auth): document reset token states
REF-AUTH-03 Refactor auth token naming refactor(auth): align reset token naming

Порядок:

text
1. Fix bug with regression test.
2. Update docs for exact behavior.
3. Refactor naming only after tests are green.

Если docs update маленький и напрямую фиксирует changed contract, его можно включить в first commit. Но "переписать всю документацию" нельзя.

Пример 3. Agent workflow task

Task:

text
AGENT-WF-01:
Plan Mode must not edit files.

One change:

text
Add workflow eval and mode guard that prevents write tools in Plan Mode.

Related files:

text
agent/policy/modes.ts
evals/agent_workflow/plan_mode_no_write_tools.yaml
docs/development/agent-workflow.md, if exact policy is documented

Unrelated:

text
RAG citation prompts
reviewer agent rubric
billing tool permissions
UI theme

Commit:

text
test(agent): enforce Plan Mode read-only behavior

Verification:

text
eval_plan_mode_no_write_tools: passed
eval_act_mode_can_edit_after_approval: passed

Здесь "one change" включает и eval, и policy. Но только для одного behavior.

Пример 4. Bug fix task

Bug:

text
Checkout accepts negative quantity.

Bad agent task:

text
Fix checkout validation and improve cart, payment and order code.

Good agent task:

text
BUG-CHECKOUT-07:
Negative quantity must be rejected before order total calculation.

Scope:
- add failing regression test;
- fix quantity validation boundary;
- run checkout validation tests.

Out of scope:
- payment provider integration;
- cart UI redesign;
- tax calculation refactor;
- dependency updates.

Commit:

text
fix(checkout): reject negative quantities

Теперь bug fix можно проверить и откатить отдельно от payment или UI changes.

Как агент должен планировать one change

Перед edits агент должен составить короткий task boundary.

Формат:

text
Task:
<task id and goal>

One change:
<one sentence>

In scope:
- ...

Out of scope:
- ...

Expected files:
- ...

Verification:
- ...

Stop conditions:
- ...

Пример:

text
Task:
AUTH-RESET-04: reject reused reset tokens.

One change:
Add consumed-token rejection and regression coverage.

In scope:
- reset token service/repository
- password reset regression test

Out of scope:
- password policy
- reset email template
- UI redesign
- dependency updates

Expected files:
- src/auth/resetTokenService.ts
- tests/auth/resetToken.test.ts

Verification:
- targeted regression test
- password reset test file

Stop conditions:
- schema migration required
- existing spec contradicts expected error
- fix requires changing public API response contract

Такой plan делает границы проверяемыми до того, как агент изменит файлы.

Prompt-шаблоны

Prompt 1. One-change planning

text
Work on this as one task - one change.

Before editing, produce:
- task ID / goal;
- one-sentence change statement;
- in-scope files or areas;
- out-of-scope files or areas;
- expected tests/evals;
- stop conditions.

Do not edit files until the boundary is clear.

Task:
<task>

Цель: не дать агенту начать с широкой реализации.

Prompt 2. Execution with boundary

text
Execute only the agreed one change.

Rules:
- keep the diff scoped to the task;
- do not perform drive-by refactors;
- do not update dependencies unless explicitly required;
- do not reformat unrelated files;
- do not change unrelated tests;
- if you find an unrelated issue, report it as follow-up;
- stop if scope must expand.

Before final answer:
- run targeted verification;
- review git diff --stat;
- list changed files and why each belongs.

Цель: удержать агента в пределах task.

Prompt 3. Mixed diff cleanup

text
Review the current diff for one task - one change.

Classify every changed file:
- related;
- maybe related, needs explanation;
- unrelated;
- pre-existing user change.

Do not revert user changes.
For changes you made that are unrelated, propose removal or split into follow-up tasks.
Show the cleaned commit plan.

Цель: почистить diff перед commit.

Prompt 4. Commit plan

text
Prepare a commit plan.

Include:
- task ID;
- one change statement;
- files to stage;
- files not to stage and why;
- verification commands/results;
- commit message;
- residual risks.

Do not commit until explicitly approved.

Цель: отделить review от commit action.

Prompt 5. Autonomous commit, если разрешено

text
After verification passes:
- stage only related files;
- review staged diff;
- create one commit tied to the task ID;
- do not include unrelated changes;
- report commit message and verification evidence.

Цель: безопасный commit step в более зрелом workflow.

Commit plan template

Перед commit полезно заполнить:

text
Task ID:

One change:

Acceptance Criteria:

Changed files to stage:
- path: reason

Changed files not staged:
- path: reason

Verification:
- command: result

Not run:
- command/check: reason

Commit message:

Residual risks:

Пример:

text
Task ID:
BUG-AUTH-12 / AUTH-RESET-04

One change:
Reject reused reset tokens and add regression coverage.

Acceptance Criteria:
Second use of token fails and password remains unchanged.

Changed files to stage:
- src/auth/resetTokenService.ts: adds consumed token guard
- tests/auth/resetToken.test.ts: adds regression test

Changed files not staged:
- docs/notes.md: pre-existing user notes

Verification:
- pytest tests/auth/test_reset_token.py::test_reuse_rejected: passed
- pytest tests/auth/test_reset_token.py: passed

Not run:
- browser E2E reset flow: not in this task

Commit message:
fix(auth): reject reused reset tokens

Residual risks:
Concurrent double-submit behavior needs separate test.

Reviewability budget

Нельзя задать универсальный лимит строк, но можно использовать warning signs.

Diff требует split, если:

  • затронуто больше 2-3 layers без явной причины;
  • больше одного independent acceptance criterion;
  • есть dependency или lockfile change без отдельной задачи;
  • в diff есть formatting всего файла;
  • tests и production changes не соответствуют друг другу;
  • reviewer не может описать change одним предложением;
  • rollback затронет unrelated behavior;
  • diff стал больше, чем команда может review за один заход.

Пример условного budget:

Сигнал Что сделать
1-3 связанных файла Обычно нормально.
4-8 файлов Проверить, все ли относятся к одному behavior.
9+ файлов Скорее всего нужен split или отдельное объяснение.
300-500+ строк diff Review risk растет.
Several layers: DB + API + UI + docs Рассмотреть task graph.
Generated files large Требуется source explanation.

Это не жесткий закон. Маленькая migration может затронуть много файлов. Но чем больше diff, тем выше обязанность объяснения.

Как stage только one change

Если diff уже получился смешанным, commit должен включать только related changes.

Команды:

bash
git status --short
git diff --stat
git diff
git add path/to/related-file
git diff --staged

Если файл содержит и related, и unrelated hunks:

bash
git add -p

Но лучший workflow - не создавать смешанный файл. Patch staging полезен, но он не должен становиться оправданием плохих task boundaries.

Опасно:

bash
git add .

Допустимо только после review всего diff.

Связь с tests

One change должен иметь проверку, которая доказывает именно этот change.

Таблица:

Change Verification
Reject reused reset token Regression/integration test for token reuse.
Add endpoint validation API contract or integration test.
Update Plan Mode policy Workflow eval with tool trace assertion.
Add skill trigger Trigger eval for skill discovery.
Fix RAG citation omission Dataset eval for citation presence and source support.
Update docs only Markdown/link checks if available, diff review.
Refactor only Existing tests prove behavior unchanged.

Если verification не связана с change, она дает мало confidence.

Плохо:

text
Changed auth token logic.
Verification: npm run lint.

Lint полезен, но не доказывает auth behavior.

Лучше:

text
Changed auth token logic.
Verification:
- token reuse regression test
- password reset test file
- lint

One change и refactor

Refactor может быть отдельной task:

text
REF-AUTH-03:
Rename ResetTokenService methods for consistency.

Verification:

text
Existing auth tests pass.
No behavior change expected.

Refactor может быть частью feature/fix только если он локален и нужен для изменения.

Пример допустимо:

text
To reject consumed tokens, extracted assertTokenUsable() from resetPassword().
No public behavior changed except reused-token rejection.

Пример плохо:

text
While fixing token reuse, agent reorganized all auth services.

Если хочется refactor после fix, лучший порядок:

text
Commit 1: fix bug with regression test
Commit 2: refactor auth token naming with tests unchanged

Так rollback bug fix и rollback refactor не связаны.

One change и migrations

Migrations повышают риск. Иногда их нужно выделять.

Пример:

text
Task:
Reject reused reset token.

Implementation requires new column:
reset_tokens.consumed_at

Возможный split:

Task Change Verification
AUTH-011A Add consumed_at column and model mapping Migration apply/model test
AUTH-011B Mark token consumed on successful reset Service/integration test
AUTH-011C Reject consumed token Regression test

Если проект маленький, можно сделать в одном task. Но final report должен объяснить, что migration действительно необходима.

Stop condition:

text
Original task did not mention schema change.
Ask for approval before adding migration.

One change и generated files

Generated files могут входить в change, если они следуют из source change.

Пример:

text
Change:
Add API field `tokenState`.

Related generated files:
- OpenAPI schema
- generated TypeScript client

Тогда final report должен сказать:

text
Generated client updated from OpenAPI schema.

Плохо:

text
Generated files changed because agent ran broad build command,
but source contract did not change.

Generated diff без source reason - warning.

One change и docs

Docs-only task:

text
docs(testing): add bug fix flow lesson

Это один change, если все изменения относятся к одному уроку или одному documentation contract.

Смешанный docs diff:

text
lesson_10_02_one_task_one_change.md
lesson_03_01_architecture_as_constraint.md
README.md
package.json

Может быть valid, если task "rename term across course". Но если task была "write lesson 10.2", изменения в модуле 3 и package.json suspicious.

Для docs тоже действует:

text
One task -> one content change -> reviewable diff.

One change и PR

На раннем этапе курса полезно считать:

text
One task -> one commit -> one small PR

В реальных командах PR может включать несколько commits, если они являются частью одного small feature slice. Но для agentic development лучше начинать с маленьких PR:

  • проще review;
  • быстрее CI;
  • проще revert;
  • меньше merge conflicts;
  • проще понять contribution агента;
  • проще делегировать reviewer agent.

Плохой PR:

text
Password reset implementation, UI, docs, dependency upgrades, refactor.

Хороший набор PRs:

text
PR 1: reset token repository
PR 2: request reset endpoint
PR 3: reset password endpoint
PR 4: token reuse regression fix
PR 5: reset form UI

Да, PRs больше. Но каждый безопаснее.

Как связать one change с development loop

Из модуля 8:

text
Read -> Plan -> Test -> Implement -> Verify -> Review -> Commit

В уроке 10.2 мы уточняем:

text
Read one task
-> Plan one change
-> Test one behavior
-> Implement one scoped diff
-> Verify one outcome
-> Review one diff
-> Commit one change

Если на любом шаге появляется второй behavior, нужен split.

Как связать one change с Bug Fix Flow

Из урока 9.5:

text
Bug report
-> Reproduce
-> Root cause
-> Failing regression test
-> Fix
-> Test passes
-> Full regression
-> Review

One task - one change добавляет:

text
Fix only this root cause.
Do not include unrelated cleanup.
Commit only this regression fix.

Bug fix commit должен быть особенно revertable.

Как связать one change с multi-agent work

Если несколько агентов работают над одной feature, one task - one change становится еще важнее.

Без этого:

text
Agent A changes backend and UI.
Agent B changes tests and backend.
Agent C refactors shared auth utilities.
All diffs collide.

С one task - one change:

text
Agent A: backend endpoint
Agent B: UI form
Agent C: E2E test
Agent D: reviewer diff

Но даже так нужно изолировать work. Именно поэтому следующий урок будет про Git worktrees.

Decision table: commit, split или stop

Ситуация Действие
Diff связан с одним AC, tests проходят Commit one change.
Diff содержит unrelated files, сделанные агентом Remove or split before commit.
Diff содержит pre-existing user changes Do not revert; stage only own related changes.
Fix требует migration вне scope Stop and ask/split.
Agent found unrelated bug Report follow-up, do not fix now unless blocking.
Tests fail because of current change Fix within task before commit.
Unrelated flaky test fails Report separately; do not hide.
Dependency update needed Usually split into dependency task.
Refactor useful but not necessary Separate task after behavior change.
Public contract changed unexpectedly Stop and update spec/AC before commit.

Агент как исполнитель, не product owner

One task - one change также ограничивает роль агента.

Агент может:

  • предложить split;
  • обнаружить scope creep;
  • найти related risk;
  • написать follow-up;
  • попросить уточнение;
  • реализовать agreed change.

Агент не должен самовольно:

  • добавлять новый product behavior;
  • менять business rules;
  • менять API semantics;
  • расширять task до "лучшей архитектуры";
  • обновлять dependencies;
  • удалять tests;
  • делать broad cleanup.

Если агент считает, что scope нужно расширить, правильное действие:

text
Stop, explain, propose options.

Review по staged diff

Даже если working tree содержит больше изменений, commit должен проходить review по staged diff.

Команды:

bash
git diff --staged --stat
git diff --staged

Reviewer смотрит:

  • staged files относятся к task;
  • unstaged files не попадут в commit случайно;
  • tests соответствуют AC;
  • generated files объяснены;
  • commit message точный;
  • final evidence соответствует staged diff.

Если staged diff clean, commit можно создавать.

One-change final answer

Финальный ответ агента после task должен быть не просто summary, а доказательство границы.

Формат:

text
Task:
- AUTH-RESET-04

One change:
- Reject reused reset tokens and cover with regression test.

Changed files:
- src/auth/resetTokenService.ts: consumed-token guard
- tests/auth/resetToken.test.ts: regression test

Out of scope not changed:
- password policy
- reset email template
- UI

Verification:
- targeted regression: passed
- password reset tests: passed

Not run:
- browser E2E reset flow

Follow-up:
- concurrent double-submit race test

Такой ответ помогает review и commit.

Практика 1. Разделить mixed diff

Task:

text
AUTH-RESET-04:
Used reset token cannot be reused.

Diff:

text
 src/auth/resetTokenService.ts          | 32 +++++++++--
 tests/auth/resetToken.test.ts          | 64 +++++++++++++++++++++
 src/auth/passwordPolicy.ts             | 18 +++---
 web/components/Button.tsx              | 45 +++++++++------
 package-lock.json                      | 420 +++++++++++++++++++++++++++++++---
 docs/auth.md                           | 20 ++++++

Заполните:

File Stage? Reason
src/auth/resetTokenService.ts
tests/auth/resetToken.test.ts
src/auth/passwordPolicy.ts
web/components/Button.tsx
package-lock.json
docs/auth.md

Сформулируйте:

text
One change:

Commit message:

Verification:

Follow-up tasks:

Практика 2. Написать commit plan

Task:

text
AGENT-WF-01:
Plan Mode must not edit files.

Заполните commit plan:

text
Task ID:

One change:

Acceptance Criterion:

Files to stage:
- ...

Files not to stage:
- ...

Verification:
- ...

Commit message:

Residual risks:

Пример решения:

text
Task ID:
AGENT-WF-01

One change:
Add eval and mode guard preventing write tools in Plan Mode.

Acceptance Criterion:
Plan Mode produces plan and no write/edit tools are called.

Files to stage:
- agent/policy/modes.ts: mode guard
- evals/agent_workflow/plan_mode_no_write_tools.yaml: regression eval

Files not to stage:
- docs/rag.md: unrelated existing edit

Verification:
- npm run eval -- plan-mode: passed

Commit message:
test(agent): enforce Plan Mode read-only behavior

Residual risks:
No real external MCP server tested in this task.

Практика 3. Сформулировать stop condition

Task:

text
Fix checkout negative quantity validation.

Во время работы агент обнаружил:

text
Validation is implemented in shared pricing library.
Changing it may affect invoices, cart preview and subscription renewal.

Напишите stop report:

text
Stop condition:

Why scope expanded:

Options:
1.
2.
3.

Recommended next task:

Возможный ответ:

text
Stop condition:
Fix requires changing shared pricing validation used by invoices, cart preview and subscriptions.

Why scope expanded:
Original task expected checkout boundary only, but root cause is in shared pricing library.

Options:
1. Add regression tests for all three affected flows, then change shared library.
2. Add checkout-specific guard as temporary fix and create follow-up for shared validation.
3. Clarify intended domain ownership before implementation.

Recommended next task:
Write regression matrix for quantity validation across checkout, invoice and subscription flows.

Checklist перед началом task

text
[ ] Task ID есть
[ ] One change можно описать одним предложением
[ ] Acceptance criterion понятен
[ ] In scope указан
[ ] Out of scope указан
[ ] Expected files/areas названы
[ ] Verification target назван
[ ] Stop conditions названы
[ ] Git branch/status проверены

Checklist перед commit

text
[ ] Diff связан с одной task
[ ] Каждый staged file имеет reason
[ ] Tests/evals соответствуют AC
[ ] Нет unrelated refactor
[ ] Нет accidental formatting
[ ] Нет unexplained dependency/lockfile changes
[ ] Нет secrets/debug output
[ ] Verification выполнена или limitation указана
[ ] Commit message описывает behavior
[ ] Revert этого commit не откатит unrelated work

Типичные ошибки

Ошибка Симптом Исправление
"И заодно" в task В diff несколько unrelated outcomes Split before implementation.
Один commit на весь epic Review и rollback почти невозможны Commit per Agent Task.
Маленькая task без verification Diff маленький, но confidence низкая Добавить test/eval/manual evidence.
Drive-by refactor Behavior fix смешан с structure rewrite Separate refactor commit.
Dependency update внутри feature Большой lockfile и unclear risk Separate dependency task.
Docs rewrite внутри bug fix Review уходит в содержание docs Документировать только changed contract.
Formatting всего файла Noise hides behavior change Format only touched scope or separate task.
Commit message vague Непонятно, что сделал агент Message tied to behavior/task ID.
Agent исправляет найденный unrelated bug Scope creep Report follow-up unless blocking.
Staging через git add . В commit попали лишние файлы Stage selected files and review staged diff.
Stop condition ignored Task становится architectural rewrite Stop and propose split.

Критерии готовности

После урока студент должен уметь:

  • объяснить правило one task - one change;
  • отличить one change от одного файла или одной строки;
  • определить, когда diff смешивает несколько задач;
  • связать task ID, AC, test/eval и commit message;
  • составить task boundary для агента;
  • задать stop conditions;
  • отделить related, suspicious и unrelated changes;
  • составить commit plan;
  • решить, когда commit, split или stop;
  • применить правило к product code, bug fix, docs и AI Agent workflow.

Краткое резюме

One Task - One Change - это дисциплина маленьких проверяемых изменений.

Главная цепочка:

text
Task
-> One change
-> Small diff
-> Verification
-> Staged diff
-> Commit

Один change определяется смыслом, а не количеством файлов.

Хороший change можно:

  • описать одним предложением;
  • связать с AC или bug report;
  • проверить конкретным test/eval;
  • review за разумное время;
  • revert без отката unrelated work.

Если агент нашел соседнюю проблему, это не повод расширять текущий diff. Это повод остановиться, зафиксировать follow-up или предложить split.

Вопросы для самопроверки

  1. Почему one task - one change важнее именно в AI-generated work?
  2. Чем one change отличается от one file?
  3. Какие признаки говорят, что diff нужно split?
  4. Что должен содержать commit plan?
  5. Когда агент должен остановиться вместо продолжения implementation?

Что дальше

Следующий урок посвящен Git worktrees. Когда одна feature разбита на маленькие независимые changes, появляется возможность выполнять некоторые tasks параллельно. Worktrees позволяют дать каждому агенту отдельную рабочую директорию, branch и контекст, чтобы параллельная работа не смешивалась в одном diff.

Обновлено 03.10.2026