mister-wolf 2.15.1 → 2.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/.wolf/router.log +1 -1
- package/templates/base/AGENTS.md +3 -2
- package/templates/base/agents/executor-lead.md +4 -0
- package/templates/base/agents/mr-wolf.md +3 -2
- package/templates/base/agents/steward.md +4 -2
- package/templates/base/agents/worker-implementer.md +5 -2
- package/templates/base/agents/worker-researcher.md +4 -2
- package/templates/base/agents/worker-reviewer.md +9 -7
- package/templates/base/commands/analyze-doc.md +1 -1
- package/templates/base/commands/complain.md +1 -1
- package/templates/base/commands/doc-review.md +1 -1
- package/templates/base/playbooks/executor-lead-playbook.md +10 -5
- package/templates/base/playbooks/steward-nastavnik.md +5 -4
- package/templates/base/playbooks/worker-implementer-playbook.md +17 -7
- package/templates/base/playbooks/worker-researcher-playbook.md +5 -2
- package/templates/base/playbooks/worker-reviewer-playbook.md +21 -8
- package/templates/base/skills/finishing-a-development-branch/SKILL.md +19 -211
- package/templates/base/skills/receiving-code-review/SKILL.md +12 -28
- package/templates/base/skills/requesting-code-review/SKILL.md +11 -110
- package/templates/base/skills/test-driven-development/SKILL.md +18 -396
- package/templates/base/skills/using-git-worktrees/SKILL.md +15 -177
- package/templates/base/skills/using-skills/SKILL.md +38 -123
- package/templates/base/skills/verification-before-completion/SKILL.md +16 -157
- package/templates/base/skills/wolf-brainstorm/SKILL.md +17 -168
- package/templates/base/skills/wolf-debug/SKILL.md +15 -281
- package/templates/base/skills/wolf-design/SKILL.md +16 -35
- package/templates/base/skills/wolf-execute/SKILL.md +13 -101
- package/templates/base/skills/wolf-handoff/SKILL.md +22 -88
- package/templates/base/skills/wolf-plan/SKILL.md +18 -181
- package/templates/base/skills/wolf-review/SKILL.md +25 -64
- package/templates/base/skills/wolf-sdd/SKILL.md +17 -248
- package/templates/base/skills/wolf-skill-intake/SKILL.md +14 -57
- package/templates/base/skills/wolf-testplan/SKILL.md +15 -27
- package/templates/base/skills/writing-skills/SKILL.md +16 -30
- package/templates/opencode/plugins/wolf-router.ts +2 -1
- package/templates/opencode/plugins/wolf-session-start.js +11 -9
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: receiving-code-review
|
|
3
|
-
description:
|
|
3
|
+
description: "Разбирай замечания пользователя или ревьюера: проверь основание, ответь на каждый пункт, исправь подтверждённый дефект и повтори затронутые проверки. Не принимай и не отвергай фидбек без evidence."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
## Обзор
|
|
9
|
-
|
|
10
|
-
Фидбек владельца = высший приоритет лестницы приоритетов. Но «внедри совет» — не
|
|
11
|
-
поведение по умолчанию: ревью может быть технически неверным.
|
|
6
|
+
# Обработка ревью
|
|
12
7
|
|
|
13
8
|
## Процесс
|
|
14
9
|
|
|
15
|
-
1.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
скиллов); расхождение правил → жалоба по протоколу жалоб, не самовольная
|
|
22
|
-
правка правила.
|
|
23
|
-
5. Уроки фидбека (воспроизводимый паттерн ошибки) → `wolf add --type lesson`.
|
|
10
|
+
1. Прочитай весь набор; различи исправление факта, вопрос, дефект, предпочтение и изменение требований. Свяжи с finding_id; если его нет, создай локальный идентификатор ответа.
|
|
11
|
+
2. Проверь воспроизводимость по исходным требованиям, коду и evidence. Ответ на каждый пункт: ACCEPTED, REFUTED, DEFERRED или NEEDS_CLARIFICATION; добавь основание и действие. Эти метки — отчёт, не типы памяти.
|
|
12
|
+
3. Подтверждённый Critical/Major исправь до приёмки; Minor назначь или отложи с причиной. Пользовательское указание о цели имеет приоритет; техническую неверность рекомендации объясни и предложи способ достичь цели.
|
|
13
|
+
4. Изменение AC/scope проведи через CR и L0; не переписывай контракт, чтобы обойти находку. Конфликт действующих методик передай жалобным контуром, но не останавливай независимую полезную работу без необходимости.
|
|
14
|
+
5. Правь минимально; проверки выбери по влиянию. Коммиты делает роль с действующим разрешением. Зафиксируй revision исправления, evidence и незакрытые риски.
|
|
15
|
+
6. Запроси повторное ревью affected mandates. Отсутствие ответа ревьюера не означает одобрения; лимит циклов заканчивается явной эскалацией.
|
|
24
16
|
|
|
25
|
-
##
|
|
17
|
+
## Память
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
- Внедрение совета вслепую при явном техническом возражении.
|
|
29
|
-
- Тихое игнорирование пункта фидбека.
|
|
19
|
+
Наблюдение о конкретной незавершённой работе фиксируй задачей/заметкой; обобщаемый повторяемый паттерн — lesson с областью применимости и evidence. Не создавай правило из каждого комментария. Недоступную запись передай L1; не обходи permissions.
|
|
30
20
|
|
|
31
|
-
##
|
|
21
|
+
## Запреты
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
| --------------------------------------------------- | ------------------------------------------------ | ----------------- |
|
|
35
|
-
| Техническая строгость, не перформативное согласие | сохранено | ядро |
|
|
36
|
-
| Проверка перед внедрением | сохранено | ядро |
|
|
37
|
-
| «Совет может быть неверным» | сохранено | ядро |
|
|
38
|
-
| — | добавлено: лестница приоритетов + протокол жалоб | Wolf-переплетение |
|
|
39
|
-
| — | добавлено: уроки фидбека → память Wolf | самообучение |
|
|
23
|
+
Не изображай согласие без проверки, не игнорируй пункт молча, не превращай ревью в бесконечный косметический цикл. Техническое возражение подкрепи проверяемым основанием, а не уверенностью.
|
|
@@ -1,123 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: requesting-code-review
|
|
3
|
-
description:
|
|
3
|
+
description: "Запрашивай независимое ревью изменений перед интеграцией или при существенном риске. Передай точный диапазон изменений, требования, проверки и мандат; диспетчер L1, ревьюер L2."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Запрос ревью кода
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
> Ревью-контур executor'а: диспетчер — executor-lead, ревьюер — worker-reviewer.
|
|
8
|
+
## Подготовка
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
L1 фиксирует base_sha ДО исполнения задачи, current/head revision и dirty-state. Не используй HEAD~1 как универсальную границу: задача может включать несколько коммитов. Для незакоммиченного результата передай проверяемый diff и состояние файлов; не требуй коммита ради ревью.
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|---|---|
|
|
15
|
-
| Когда запрашивать (2 списка), контекстный шаблон ревьюера (5 полей), таблица act-on-feedback, пример, red flags Never (4) + «если ревьюер неправ» (3), интеграционные привязки | **сохранено полностью** (H6/H7: act-on-feedback и red flags переносятся дословно по смыслу) |
|
|
16
|
-
| Task tool с типом `superpowers:code-reviewer` | **заменено**: спавн worker-reviewer через {{tool.task}}; методика ревьюера — в памяти (контур лица worker-reviewer) |
|
|
17
|
-
| Внешний шаблон `agents/code-reviewer.md` | **заменено**: поля шаблона встроены в этот скилл (BASE_SHA/HEAD_SHA и др.) |
|
|
18
|
-
| Minor → «note for later» | **дополнено**: фиксация через `wolf add --type lesson` (техдолг виден следующим сессиям) |
|
|
19
|
-
| Префикс `superpowers:`, имя code-reviewer | **отброшено**: имена harness'а upstream |
|
|
12
|
+
## Пакет ревьюера
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
Передай task_id, цель, AC/REQ и утверждённый design, base/head, cwd/worktree, изменённые и релевантные файлы, contract dependencies, проверки/evidence, известные ограничения. Не передавай самооценку автора как ожидаемый вывод. Независимый reviewer проверяет код и основания, а не только пересказ.
|
|
22
15
|
|
|
23
|
-
|
|
16
|
+
Назначь мандат: соответствие, качество/интеграция или специализированный риск. Для значимых изменений проверь security, миграции и failures; для небольших — пропорциональный объём. L0 вызывает executor, L1 — worker-reviewer. Недоступное независимое ревью явно отметь, не имитируй второй голос.
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
## Результат
|
|
26
19
|
|
|
27
|
-
|
|
20
|
+
Используй контракт wolf-review: finding_id, severity, location/revision, evidence, impact; verdict APPROVED | CHANGES_REQUIRED | INCONCLUSIVE. Critical/Major блокируют приёмку; Minor — нет, кроме явно обоснованного риска. Технический долг — отдельная задача/заметка, lesson только для повторяемого знания.
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
- После каждой задачи в wolf-sdd
|
|
31
|
-
- После завершения крупной фичи
|
|
32
|
-
- Перед мержем в main
|
|
22
|
+
## Обработка
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
- Когда застрял (свежий взгляд)
|
|
36
|
-
- Перед рефакторингом (базовая проверка)
|
|
37
|
-
- После фиксации сложного бага
|
|
38
|
-
|
|
39
|
-
## Как запросить
|
|
40
|
-
|
|
41
|
-
**1. Получить git SHA:**
|
|
42
|
-
```bash
|
|
43
|
-
BASE_SHA=$(git rev-parse HEAD~1) # или origin/main
|
|
44
|
-
HEAD_SHA=$(git rev-parse HEAD)
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
**2. Диспетчеризовать воркера-ревьюера через {{tool.task}}:**
|
|
48
|
-
|
|
49
|
-
Спавн worker-reviewer; контекст ревьюера заполняет диспетчер (executor-lead). Ревьюер сам подтягивает методику перед задачей: `wolf search "worker-reviewer playbook"` (контур лица, наибольшая версия).
|
|
50
|
-
|
|
51
|
-
**Поля контекста:**
|
|
52
|
-
- `{WHAT_WAS_IMPLEMENTED}` — что только что построено
|
|
53
|
-
- `{PLAN_OR_REQUIREMENTS}` — что оно должно делать (задача из плана / бриф)
|
|
54
|
-
- `{BASE_SHA}` — стартовый коммит
|
|
55
|
-
- `{HEAD_SHA}` — конечный коммит
|
|
56
|
-
- `{DESCRIPTION}` — краткое описание
|
|
57
|
-
|
|
58
|
-
**3. Действовать по фидбеку (act-on-feedback):**
|
|
59
|
-
|
|
60
|
-
| Категория | Действие |
|
|
61
|
-
|---|---|
|
|
62
|
-
| Critical | Исправить немедленно |
|
|
63
|
-
| Important | Исправить до продолжения работы |
|
|
64
|
-
| Minor | Зафиксировать и учесть позже (`wolf add --type lesson`) |
|
|
65
|
-
|
|
66
|
-
Возражай, если ревьюер неправ (с обоснованием).
|
|
67
|
-
|
|
68
|
-
## Пример
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
[Завершена задача 2: функция верификации]
|
|
72
|
-
|
|
73
|
-
Ты: Запрошу ревью перед продолжением.
|
|
74
|
-
|
|
75
|
-
BASE_SHA=$(git log --oneline | grep "Task 1" | head -1 | awk '{print $1}')
|
|
76
|
-
HEAD_SHA=$(git rev-parse HEAD)
|
|
77
|
-
|
|
78
|
-
[Диспетчеризую worker-reviewer через {{tool.task}}]
|
|
79
|
-
WHAT_WAS_IMPLEMENTED: Функции verifyIndex() и repairIndex() для индекса диалогов
|
|
80
|
-
PLAN_OR_REQUIREMENTS: Задача 2 из docs/plans/deployment-plan.md
|
|
81
|
-
BASE_SHA: a7981ec
|
|
82
|
-
HEAD_SHA: 3df7661
|
|
83
|
-
DESCRIPTION: Добавлены verifyIndex() и repairIndex() с 4 типами проблем
|
|
84
|
-
|
|
85
|
-
[Воркер вернул]:
|
|
86
|
-
Strengths: чистая архитектура, настоящие тесты
|
|
87
|
-
Issues:
|
|
88
|
-
Important: нет индикаторов прогресса
|
|
89
|
-
Minor: магическое число (100) для интервала отчётности
|
|
90
|
-
Assessment: готов к продолжению
|
|
91
|
-
|
|
92
|
-
Ты: [фиксируешь индикаторы прогресса]
|
|
93
|
-
[Minor фиксируешь: wolf add --type lesson "техдолг: магическое число 100 ..."]
|
|
94
|
-
[Продолжаешь задачу 3]
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Интеграция с процессами
|
|
98
|
-
|
|
99
|
-
**wolf-sdd (субагентная разработка):**
|
|
100
|
-
- Ревью после КАЖДОЙ задачи
|
|
101
|
-
- Ловить проблемы до того, как они накопятся
|
|
102
|
-
- Исправить до перехода к следующей задаче
|
|
103
|
-
|
|
104
|
-
**wolf-execute (исполнение плана):**
|
|
105
|
-
- Ревью после каждого батча (3 задачи)
|
|
106
|
-
- Получить фидбек, применить, продолжить
|
|
107
|
-
|
|
108
|
-
**Ad-hoc разработка:**
|
|
109
|
-
- Ревью перед мержем
|
|
110
|
-
- Ревью при застревании
|
|
111
|
-
|
|
112
|
-
## Red flags
|
|
113
|
-
|
|
114
|
-
**Никогда:**
|
|
115
|
-
- Не пропускать ревью со словами «это же просто»
|
|
116
|
-
- Не игнорировать Critical-находки
|
|
117
|
-
- Не продолжать с неисправленными Important-находками
|
|
118
|
-
- Не спорить с валидным техническим фидбеком
|
|
119
|
-
|
|
120
|
-
**Если ревьюер неправ:**
|
|
121
|
-
- Возразить с техническим обоснованием
|
|
122
|
-
- Показать код/тесты, доказывающие работу
|
|
123
|
-
- Попросить уточнение
|
|
24
|
+
Прими фидбек через receiving-code-review. Перед повторным ревью обозначь изменённые версии и закрываемые finding IDs. Сохрани действительные результаты неизменённых проверок; повтори затронутые. Открытие PR и его приёмка — разные состояния, отчёт должен это различать.
|
|
@@ -1,413 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-driven-development
|
|
3
|
-
description:
|
|
3
|
+
description: "Проверяй новое поведение и багфиксы через чувствительный к дефекту тест до реализации. Для рефакторинга сохраняй существующее поведение characterization-тестами; выбирай проверку по риску и контракту."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Тестовая дисциплина исполнения
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
> Адресат: worker-implementer — пассивный процесс: читаешь и следуешь в рамках своей единственной задачи, без диспетчеризации.
|
|
8
|
+
## Вход
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
L2 получает назначенные AC, сценарии test-plan, allowlist и команды профиля проекта. Читай необходимый существующий код. Не меняй AC и не добавляй продуктовые функции ради удобства тестирования без согласования.
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
15
|
-
| Iron Law, цикл RED-GREEN-REFACTOR, обязательные верификации RED/GREEN, dot-диаграмма | **сохранено** дословно (перевод) |
|
|
16
|
-
| Таблица рационализаций (11), red flags (13), «Why Order Matters» (5 аргументов), анти-паттерны тестирования (3), чеклист верификации (8), «When Stuck» (4), примеры Good/Bad, пример багфикса | **сохранено полностью** по смыслу дословно (H7) |
|
|
17
|
-
| `npm test <путь>` | **заменено**: точечный прогон — `npx vitest run <путь>` (стек проекта — vitest); полный — `npm run check` |
|
|
18
|
-
| «Ask your human partner» (исключения из Iron Law) | **заменено**: явное разрешение владельца; воркер эскалирует запрос через executor-lead, сам не решает |
|
|
19
|
-
| Чеклист верификации | **дополнено**: механика {{tool.todowrite}} — один пункт на чекбокс |
|
|
20
|
-
| Ссылка на внешний `@testing-anti-patterns.md` | **отброшено**: reference-файл вне шаблона; суть (3 пункта) встроена в раздел «Анти-паттерны тестирования» |
|
|
21
|
-
| Контур лица | **добавлено**: до задачи — `wolf search "worker-implementer playbook"` (брать наибольшую версию) |
|
|
12
|
+
## Новое поведение и багфикс
|
|
22
13
|
|
|
23
|
-
|
|
14
|
+
1. Напиши минимальную проверку наблюдаемого контракта с независимым ожидаемым результатом. Для бага воспроизведи исходный симптом.
|
|
15
|
+
2. Запусти RED. Проверь, что причиной является отсутствующее/неверное поведение, а не опечатка, сломанный setup или недоступная зависимость. Отсутствующий публичный интерфейс допустим в начале, но после его появления проверка должна проверять поведение.
|
|
16
|
+
3. Напиши минимальную реализацию; запусти GREEN и связанные регрессии. Не ослабляй assertion ради зелёного результата; ошибку самого теста исправляй с обоснованием.
|
|
17
|
+
4. Рефакторь в пределах задачи, сохраняя зелёные проверки. Зафиксируй RED/GREEN evidence и область регрессий.
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
## Существующее поведение и рефакторинг
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
Characterization-тесты могут проходить сразу: они фиксируют baseline. Затем проверь, что изменение сохраняет контракт. Не требуй искусственно ломать рабочий код для каждого такого теста. Чувствительность важной регрессионной проверки подтверди на исходной версии или изолированным временным возвратом дефекта; чужие изменения не откатывай.
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
## Если код уже написан
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
Не удаляй результат автоматически. Сохрани его и отметь отклонение процесса; для нового поведения код-первый — задокументированное отклонение, которое L1 обязан провести через ревью качества тестов (минимум DONE_WITH_CONCERNS), а не молчаливая норма. Добавь независимые проверки по требованиям. Для исправления дефекта покажи падение на baseline и прохождение на текущем коде. Если это невозможно, обозначь предел уверенности и передай L1. Историю RED не выдумывай.
|
|
32
26
|
|
|
33
|
-
|
|
27
|
+
## Качество тестов
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
- Багфиксы
|
|
37
|
-
- Рефакторинг
|
|
38
|
-
- Изменения поведения
|
|
29
|
+
Проверяй публичное поведение, границы, ошибки и инварианты; не требуй отдельного теста для каждой внутренней функции. Моки используй для внешних границ, сохраняя интеграционную проверку там, где взаимодействие несёт риск. Fixtures должны быть изолированы, seed/time контролируемы, cleanup безопасен. Не тестируй только конфигурацию собственного мока.
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
Для документации, конфигураций и генерации выбирай валидатор, snapshot, smoke или воспроизводимую ручную проверку. Отказ от релевантной автоматической проверки должен иметь основание по политике проекта, а не обязательный вопрос владельцу на каждую мелочь.
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
- Генерированный код
|
|
44
|
-
- Конфигурационные файлы
|
|
33
|
+
## Готовность
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Iron Law
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
НИКАКОГО ПРОДАКШЕН-КОДА БЕЗ ПАДАЮЩЕГО ТЕСТА
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Написал код до теста? Удали. Начни заново.
|
|
55
|
-
|
|
56
|
-
**Без исключений:**
|
|
57
|
-
|
|
58
|
-
- Не оставляй «как референс»
|
|
59
|
-
- Не «адаптируй» его при написании тестов
|
|
60
|
-
- Не смотри на него
|
|
61
|
-
- Удалить означает удалить
|
|
62
|
-
|
|
63
|
-
Реализуй с нуля из тестов. Точка.
|
|
64
|
-
|
|
65
|
-
## Красный-Зелёный-Рефакторинг
|
|
66
|
-
|
|
67
|
-
```dot
|
|
68
|
-
digraph tdd_cycle {
|
|
69
|
-
rankdir=LR;
|
|
70
|
-
red [label="КРАСНЫЙ\nНапиши падающий тест", shape=box, style=filled, fillcolor="#ffcccc"];
|
|
71
|
-
verify_red [label="Падает\nпо правильной причине", shape=diamond];
|
|
72
|
-
green [label="ЗЕЛЁНЫЙ\nМинимальный код", shape=box, style=filled, fillcolor="#ccffcc"];
|
|
73
|
-
verify_green [label="Проходит\nВсё зелёное", shape=diamond];
|
|
74
|
-
refactor [label="РЕФАКТОРИНГ\nПрибраться", shape=box, style=filled, fillcolor="#ccccff"];
|
|
75
|
-
next [label="Дальше", shape=ellipse];
|
|
76
|
-
|
|
77
|
-
red -> verify_red;
|
|
78
|
-
verify_red -> green [label="да"];
|
|
79
|
-
verify_red -> red [label="не та\nпричина"];
|
|
80
|
-
green -> verify_green;
|
|
81
|
-
verify_green -> refactor [label="да"];
|
|
82
|
-
verify_green -> green [label="нет"];
|
|
83
|
-
refactor -> verify_green [label="остаёмся\nзелёными"];
|
|
84
|
-
verify_green -> next;
|
|
85
|
-
next -> red;
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### КРАСНЫЙ — напиши падающий тест
|
|
90
|
-
|
|
91
|
-
Напиши один минимальный тест, показывающий, что должно происходить.
|
|
92
|
-
|
|
93
|
-
<Good>
|
|
94
|
-
```typescript
|
|
95
|
-
test('повторяет неудачную операцию 3 раза', async () => {
|
|
96
|
-
let attempts = 0;
|
|
97
|
-
const operation = () => {
|
|
98
|
-
attempts++;
|
|
99
|
-
if (attempts < 3) throw new Error('fail');
|
|
100
|
-
return 'success';
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const result = await retryOperation(operation);
|
|
104
|
-
|
|
105
|
-
expect(result).toBe('success');
|
|
106
|
-
expect(attempts).toBe(3);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
````
|
|
110
|
-
Ясное имя, тестирует реальное поведение, одно
|
|
111
|
-
</Good>
|
|
112
|
-
|
|
113
|
-
<Bad>
|
|
114
|
-
```typescript
|
|
115
|
-
test('retry works', async () => {
|
|
116
|
-
const mock = jest.fn()
|
|
117
|
-
.mockRejectedValueOnce(new Error())
|
|
118
|
-
.mockRejectedValueOnce(new Error())
|
|
119
|
-
.mockResolvedValueOnce('success');
|
|
120
|
-
await retryOperation(mock);
|
|
121
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
|
122
|
-
});
|
|
123
|
-
````
|
|
124
|
-
|
|
125
|
-
Расплывчатое имя, тестирует мок, а не код
|
|
126
|
-
</Bad>
|
|
127
|
-
|
|
128
|
-
**Требования:**
|
|
129
|
-
|
|
130
|
-
- Одно поведение
|
|
131
|
-
- Ясное имя
|
|
132
|
-
- Реальный код (моки — только при неизбежности)
|
|
133
|
-
|
|
134
|
-
### Верифицируй КРАСНЫЙ — посмотри, как падает
|
|
135
|
-
|
|
136
|
-
**ОБЯЗАТЕЛЬНО. Никогда не пропускай.**
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
npx vitest run <путь-к-тесту>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Подтверди:
|
|
143
|
-
|
|
144
|
-
- Тест падает (а не ошибается)
|
|
145
|
-
- Сообщение об ошибке ожидаемое
|
|
146
|
-
- Падает из-за отсутствия фичи (не из-за опечаток)
|
|
147
|
-
|
|
148
|
-
**Тест проходит?** Ты тестируешь существующее поведение. Почини тест.
|
|
149
|
-
|
|
150
|
-
**Тест ошибается?** Почини ошибку, гоняй, пока не упадёт корректно.
|
|
151
|
-
|
|
152
|
-
### ЗЕЛЁНЫЙ — минимальный код
|
|
153
|
-
|
|
154
|
-
Напиши простейший код, чтобы тест прошёл.
|
|
155
|
-
|
|
156
|
-
<Good>
|
|
157
|
-
```typescript
|
|
158
|
-
async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
|
|
159
|
-
for (let i = 0; i < 3; i++) {
|
|
160
|
-
try {
|
|
161
|
-
return await fn();
|
|
162
|
-
} catch (e) {
|
|
163
|
-
if (i === 2) throw e;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
throw new Error('unreachable');
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
Ровно столько, чтобы пройти
|
|
170
|
-
</Good>
|
|
171
|
-
|
|
172
|
-
<Bad>
|
|
173
|
-
```typescript
|
|
174
|
-
async function retryOperation<T>(
|
|
175
|
-
fn: () => Promise<T>,
|
|
176
|
-
options?: {
|
|
177
|
-
maxRetries?: number;
|
|
178
|
-
backoff?: 'linear' | 'exponential';
|
|
179
|
-
onRetry?: (attempt: number) => void;
|
|
180
|
-
}
|
|
181
|
-
): Promise<T> {
|
|
182
|
-
// YAGNI
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
Оверинжиниринг
|
|
186
|
-
</Bad>
|
|
187
|
-
|
|
188
|
-
Не добавляй фичи, не рефакторь другой код, не «улучшай» сверх теста.
|
|
189
|
-
|
|
190
|
-
### Верифицируй ЗЕЛЁНЫЙ — посмотри, как проходит
|
|
191
|
-
|
|
192
|
-
**ОБЯЗАТЕЛЬНО.**
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
npx vitest run <путь-к-тесту>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Подтверди:
|
|
199
|
-
|
|
200
|
-
- Тест проходит
|
|
201
|
-
- Остальные тесты всё ещё проходят
|
|
202
|
-
- Вывод чистый (без ошибок и предупреждений)
|
|
203
|
-
|
|
204
|
-
**Тест упал?** Чини код, а не тест.
|
|
205
|
-
|
|
206
|
-
**Другие тесты упали?** Чини сейчас.
|
|
207
|
-
|
|
208
|
-
### РЕФАКТОРИНГ — приберись
|
|
209
|
-
|
|
210
|
-
Только после зелёного:
|
|
211
|
-
|
|
212
|
-
- Убери дублирование
|
|
213
|
-
- Улучши имена
|
|
214
|
-
- Вынеси хелперы
|
|
215
|
-
|
|
216
|
-
Тесты остаются зелёными. Поведение не добавляется.
|
|
217
|
-
|
|
218
|
-
### Повтори
|
|
219
|
-
|
|
220
|
-
Следующий падающий тест для следующей фичи.
|
|
221
|
-
|
|
222
|
-
## Хорошие тесты
|
|
223
|
-
|
|
224
|
-
| Качество | Хорошо | Плохо |
|
|
225
|
-
| ----------------- | ------------------------------------- | ------------------------------------------ |
|
|
226
|
-
| **Минимальность** | Одно поведение. «И» в имени? Раздели. | `test('проверяет email, домен и пробелы')` |
|
|
227
|
-
| **Ясность** | Имя описывает поведение | `test('test1')` |
|
|
228
|
-
| **Намерение** | Демонстрирует желаемый API | Затуманивает, что код должен делать |
|
|
229
|
-
|
|
230
|
-
## Почему важен порядок
|
|
231
|
-
|
|
232
|
-
**«Я напишу тесты после, чтобы проверить, что работает»**
|
|
233
|
-
|
|
234
|
-
Тесты, написанные после кода, проходят сразу. Прохождение сразу не доказывает ничего:
|
|
235
|
-
|
|
236
|
-
- Может тестировать не то
|
|
237
|
-
- Может тестировать реализацию, а не поведение
|
|
238
|
-
- Может упускать пограничные случаи, которые ты забыл
|
|
239
|
-
- Ты никогда не видел, как тест ловит баг
|
|
240
|
-
|
|
241
|
-
Тест-первый заставляет увидеть падение теста — доказательство, что он реально что-то проверяет.
|
|
242
|
-
|
|
243
|
-
**«Я уже вручно протестировал все пограничные случаи»**
|
|
244
|
-
|
|
245
|
-
Ручное тестирование ад-хок. Ты думаешь, что проверил всё, но:
|
|
246
|
-
|
|
247
|
-
- Нет записи о том, что проверено
|
|
248
|
-
- Нельзя перезапустить при изменении кода
|
|
249
|
-
- Легко забыть случаи под давлением
|
|
250
|
-
- «Работало, когда я пробовал» ≠ исчерпывающе
|
|
251
|
-
|
|
252
|
-
Автотесты систематичны. Они выполняются одинаково каждый раз.
|
|
253
|
-
|
|
254
|
-
**«Удалить X часов работы расточительно»**
|
|
255
|
-
|
|
256
|
-
Ошибка невозвратных издержек. Время уже потрачено. Выбор сейчас:
|
|
257
|
-
|
|
258
|
-
- Удалить и переписать по TDD (ещё X часов, высокая уверенность)
|
|
259
|
-
- Оставить и дописать тесты после (30 минут, низкая уверенность, вероятные баги)
|
|
260
|
-
|
|
261
|
-
«Расточительство» — держать код, которому не можешь доверять. Работающий код без настоящих тестов — техдолг.
|
|
262
|
-
|
|
263
|
-
**«TDD догматично, прагматизм означает адаптацию»**
|
|
264
|
-
|
|
265
|
-
TDD — И есть прагматизм:
|
|
266
|
-
|
|
267
|
-
- Находит баги до коммита (быстрее отладки после)
|
|
268
|
-
- Предотвращает регрессии (тесты ловят поломки сразу)
|
|
269
|
-
- Документирует поведение (тесты показывают, как использовать код)
|
|
270
|
-
- Даёт рефакторинг (меняй свободно, тесты ловят поломки)
|
|
271
|
-
|
|
272
|
-
«Прагматичные» сокращения = отладка в проде = медленнее.
|
|
273
|
-
|
|
274
|
-
**«Тесты после достигают тех же целей — важен дух, а не ритуал»**
|
|
275
|
-
|
|
276
|
-
Нет. Тесты-после отвечают «что это делает?». Тесты-первый отвечают «что это должно делать?».
|
|
277
|
-
|
|
278
|
-
Тесты-после смещены твоей реализацией: ты тестируешь то, что построил, а не то, что требуется. Верифицируешь запомненные пограничные случаи, а не обнаруженные.
|
|
279
|
-
|
|
280
|
-
Тест-первый заставляет обнаружить пограничные случаи до реализации. Тесты-после проверяют, что ты всё запомнил (ты не запомнил).
|
|
281
|
-
|
|
282
|
-
30 минут тестов после ≠ TDD. Получаешь покрытие, теряешь доказательство, что тесты работают.
|
|
283
|
-
|
|
284
|
-
## Распространённые рационализации
|
|
285
|
-
|
|
286
|
-
| Оправдание | Реальность |
|
|
287
|
-
| ------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
288
|
-
| «Слишком просто, чтобы тестировать» | Простой код ломается. Тест занимает 30 секунд. |
|
|
289
|
-
| «Напишу тесты после» | Тесты, проходящие сразу, не доказывают ничего. |
|
|
290
|
-
| «Тесты после достигают тех же целей» | Тесты-после = «что это делает?». Тесты-первый = «что это должно делать?» |
|
|
291
|
-
| «Уже протестировал вручную» | Ад-хок ≠ систематично. Нет записи, нельзя перезапустить. |
|
|
292
|
-
| «Удалить X часов работы расточительно» | Ошибка невозвратных издержек. Держать непроверенный код — техдолг. |
|
|
293
|
-
| «Оставлю как референс, напишу тесты с нуля» | Ты его адаптируешь. Это тесты-после. Удалить = удалить. |
|
|
294
|
-
| «Нужно сначала поисследовать» | Ок. Выброси исследование, начни с TDD. |
|
|
295
|
-
| «Тест сложный — дизайн неясен» | Слушай тест. Сложно тестировать = сложно использовать. |
|
|
296
|
-
| «TDD меня замедлит» | TDD быстрее отладки. Прагматизм = тест-первый. |
|
|
297
|
-
| «Ручной тест быстрее» | Ручной не доказывает пограничные случаи. Перепроверять при каждом изменении. |
|
|
298
|
-
| «В существующем коде нет тестов» | Ты его улучшаешь. Добавляй тесты для существующего кода. |
|
|
299
|
-
|
|
300
|
-
## Red flags — ОСТАНОВИСЬ и начни заново
|
|
301
|
-
|
|
302
|
-
- Код до теста
|
|
303
|
-
- Тест после реализации
|
|
304
|
-
- Тест проходит сразу
|
|
305
|
-
- Не можешь объяснить, почему тест упал
|
|
306
|
-
- Тесты «добавим позже»
|
|
307
|
-
- Рационализация «только этот раз»
|
|
308
|
-
- «Я уже вручную протестировал»
|
|
309
|
-
- «Тесты после достигают той же цели»
|
|
310
|
-
- «Дело в духе, а не в ритуале»
|
|
311
|
-
- «Оставлю как референс» или «адаптирую существующий код»
|
|
312
|
-
- «Уже потратил X часов, удалять расточительно»
|
|
313
|
-
- «TDD догматично, я прагматик»
|
|
314
|
-
- «Это другой случай, потому что...»
|
|
315
|
-
|
|
316
|
-
**Любой из этих пунктов означает: удали код. Начни заново по TDD.**
|
|
317
|
-
|
|
318
|
-
## Пример: багфикс
|
|
319
|
-
|
|
320
|
-
**Баг:** принимается пустой email
|
|
321
|
-
|
|
322
|
-
**КРАСНЫЙ**
|
|
323
|
-
|
|
324
|
-
```typescript
|
|
325
|
-
test('отклоняет пустой email', async () => {
|
|
326
|
-
const result = await submitForm({ email: '' });
|
|
327
|
-
expect(result.error).toBe('Email required');
|
|
328
|
-
});
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
**Верифицируй КРАСНЫЙ**
|
|
332
|
-
|
|
333
|
-
```bash
|
|
334
|
-
$ npx vitest run <путь-к-тесту>
|
|
335
|
-
FAIL: expected 'Email required', got undefined
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
**ЗЕЛЁНЫЙ**
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
function submitForm(data: FormData) {
|
|
342
|
-
if (!data.email?.trim()) {
|
|
343
|
-
return { error: 'Email required' };
|
|
344
|
-
}
|
|
345
|
-
// ...
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
**Верифицируй ЗЕЛЁНЫЙ**
|
|
350
|
-
|
|
351
|
-
```bash
|
|
352
|
-
$ npx vitest run <путь-к-тесту>
|
|
353
|
-
PASS
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
**РЕФАКТОРИНГ**
|
|
357
|
-
Вынеси валидацию для нескольких полей, если нужно.
|
|
358
|
-
|
|
359
|
-
## Чеклист верификации
|
|
360
|
-
|
|
361
|
-
Перед отметкой работы как завершённой размести пункты в {{tool.todowrite}} (один пункт — один чекбокс) и отметь по факту:
|
|
362
|
-
|
|
363
|
-
- [ ] У каждой новой функции/метода есть тест
|
|
364
|
-
- [ ] Видел каждый тест падающим до реализации
|
|
365
|
-
- [ ] Каждый тест падал по ожидаемой причине (фича отсутствует, не опечатка)
|
|
366
|
-
- [ ] Написал минимальный код для прохождения каждого теста
|
|
367
|
-
- [ ] Все тесты проходят
|
|
368
|
-
- [ ] Вывод чистый (без ошибок и предупреждений)
|
|
369
|
-
- [ ] Тесты используют реальный код (моки — только при неизбежности)
|
|
370
|
-
- [ ] Пограничные случаи и ошибки покрыты
|
|
371
|
-
|
|
372
|
-
Не можешь отметить все пункты? Ты пропустил TDD. Начни заново.
|
|
373
|
-
|
|
374
|
-
## Когда застрял
|
|
375
|
-
|
|
376
|
-
| Проблема | Решение |
|
|
377
|
-
| ------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
378
|
-
| Не знаю, как тестировать | Напиши желаемый API. Сначала напиши assertion. Запроси подсказку владельца через executor-lead. |
|
|
379
|
-
| Тест слишком сложный | Дизайн слишком сложный. Упрости интерфейс. |
|
|
380
|
-
| Приходится мокать всё | Код слишком связан. Используй внедрение зависимостей. |
|
|
381
|
-
| Подготовка теста огромная | Вынеси хелперы. Всё ещё сложно? Упрости дизайн. |
|
|
382
|
-
|
|
383
|
-
## Интеграция с отладкой
|
|
384
|
-
|
|
385
|
-
Найден баг? Напиши падающий тест, воспроизводящий его. Пройди цикл TDD. Тест доказывает фикс и предотвращает регрессию.
|
|
386
|
-
|
|
387
|
-
Никогда не чини баги без теста.
|
|
388
|
-
|
|
389
|
-
## Анти-паттерны тестирования
|
|
390
|
-
|
|
391
|
-
- Тестирование поведения мока вместо реального поведения
|
|
392
|
-
- Тест-методы в продакшен-классах
|
|
393
|
-
- Моки без понимания зависимостей
|
|
394
|
-
|
|
395
|
-
## Интеграция с Wolf
|
|
396
|
-
|
|
397
|
-
- **Контур лица**: до задачи — `wolf search "worker-implementer playbook"` (наибольшая версия); методика эволюционирует в памяти, этот файл — только процесс.
|
|
398
|
-
- **Полная верификация** в конце задачи — `npm run check`.
|
|
399
|
-
- **Урок**: наткнулся на нетривиальную ловушку TDD-цикла — зафиксируй `wolf add --type lesson`, чтобы следующий воркер её обошёл.
|
|
400
|
-
|
|
401
|
-
## Финальное правило
|
|
402
|
-
|
|
403
|
-
```
|
|
404
|
-
Продакшен-код → тест существует и упал первым
|
|
405
|
-
Иначе → не TDD
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
Без исключений — кроме явного разрешения владельца.
|
|
409
|
-
|
|
410
|
-
## Конвейер (2.15)
|
|
411
|
-
|
|
412
|
-
Сценарии `docs/dev/<дата>-<slug>/test-plan.md` — заготовки КРАСНОЙ фазы: TDD-цикл
|
|
413
|
-
фичи конвейера начинается с переноса сценария в падающий тест, не с изобретения теста.
|
|
35
|
+
AC покрыты, исходный дефект воспроизводился, новые проверки чувствительны к неверному поведению, связанные регрессии пройдены или ограничение явно указано. RESULT не подменяет независимое ревью и приёмку. Коммиты — зона L1.
|