@rt-tools/agent-kit 0.8.2 → 0.8.3

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.
Files changed (66) hide show
  1. package/README.md +1 -0
  2. package/assets/agents/rules-reviewer.md +83 -0
  3. package/assets/checks/check-dupes.mjs +66 -6
  4. package/assets/checks/check-specs.mjs +100 -15
  5. package/assets/checks/rt-kit-checks.config.mjs +9 -0
  6. package/assets/commands/feedback.md +95 -0
  7. package/assets/commands/rules-review.md +98 -0
  8. package/assets/commands/skill-curator.md +39 -22
  9. package/assets/docs/GLOSSARY.md +21 -20
  10. package/assets/hooks/reuse-first-guard.sh +16 -2
  11. package/assets/hooks/skill-gate.sh +1 -1
  12. package/assets/hooks/task-flow-guard.sh +16 -2
  13. package/assets/hooks/waiting-turn-guard.sh +87 -0
  14. package/assets/laws/delivery.md +28 -0
  15. package/assets/laws/project-documentation.md +18 -0
  16. package/assets/laws/work-conduct.md +16 -0
  17. package/assets/patterns/git-workflow-commit.azure.md +74 -2
  18. package/assets/patterns/git-workflow-commit.github.md +75 -2
  19. package/assets/patterns/git-workflow-commit.gitlab.md +75 -4
  20. package/assets/patterns/git-workflow-docker.md +30 -0
  21. package/assets/patterns/task-flow-close.md +154 -47
  22. package/assets/patterns/task-flow-handoff.md +1 -1
  23. package/assets/patterns/task-flow-resume.md +3 -3
  24. package/assets/patterns/task-flow-start.md +32 -5
  25. package/assets/rules/angular-patterns.md +22 -0
  26. package/assets/rules/api-layer.md +25 -0
  27. package/assets/rules/browser-verification.md +32 -0
  28. package/assets/rules/component-structure.md +21 -0
  29. package/assets/rules/dependencies.md +22 -0
  30. package/assets/rules/doc-style.md +24 -0
  31. package/assets/rules/entity-conventions.needs-admin.md +21 -0
  32. package/assets/rules/entity-models.md +21 -0
  33. package/assets/rules/git-workflow.azure.md +50 -1
  34. package/assets/rules/git-workflow.github.md +48 -2
  35. package/assets/rules/git-workflow.gitlab.md +49 -1
  36. package/assets/rules/lib-layers.md +25 -0
  37. package/assets/rules/lists.md +27 -0
  38. package/assets/rules/navigation.md +21 -0
  39. package/assets/rules/observability.needs-app.md +23 -0
  40. package/assets/rules/permissions.md +23 -0
  41. package/assets/rules/platform-access.md +21 -0
  42. package/assets/rules/reuse-first.md +20 -0
  43. package/assets/rules/seo.md +19 -0
  44. package/assets/rules/shared-code.md +19 -0
  45. package/assets/rules/spec-driven.md +32 -0
  46. package/assets/rules/styling-bem.md +19 -0
  47. package/assets/rules/task-flow.md +107 -17
  48. package/assets/rules/testing.md +31 -0
  49. package/assets/rules/translations.md +21 -0
  50. package/assets/rules/typescript-conventions.md +21 -0
  51. package/assets/samples/specs/_template/spec.md +83 -0
  52. package/assets/samples/tasks/_template/grill.md +28 -0
  53. package/assets/samples/tasks/_template/plan.md +39 -0
  54. package/assets/samples/tasks/_template/progress.md +23 -0
  55. package/assets/skills/agent-kit.md +16 -2
  56. package/assets/templates/rule.md +31 -2
  57. package/lib/commands.d.ts.map +1 -1
  58. package/lib/commands.js +1 -0
  59. package/lib/commands.js.map +1 -1
  60. package/lib/config.d.ts +10 -1
  61. package/lib/config.d.ts.map +1 -1
  62. package/lib/config.js +4 -0
  63. package/lib/config.js.map +1 -1
  64. package/package.json +1 -1
  65. package/rt-tools-agent-kit-0.8.3.tgz +0 -0
  66. package/rt-tools-agent-kit-0.8.2.tgz +0 -0
@@ -6,8 +6,14 @@ argument-hint: '[пусто | <акцент, на что смотреть в п
6
6
  Запусти агента `skill-curator` на разбор только что закрытой задачи. Акцент от пользователя:
7
7
  `$ARGUMENTS`
8
8
 
9
- Вызывается **после того, как задача сделана и проверена**, до перехода к следующей. Агент ничего
10
- не правит приносит готовые формулировки, а решение вставлять их принимает пользователь.
9
+ Вызывается **сразу за открытием PR** тем же ходом, которым работа отдана на разбор. Агент
10
+ ничего не правит: он приносит готовые формулировки, а решение вставлять их принимает
11
+ пользователь.
12
+
13
+ **Запуск фоновый, и ход на нём не кончается.** Пока агент работает, берётся следующая задача:
14
+ он ничего не спрашивает и быстрее от ожидания не идёт. Шаги 1 и 2 делаются до запуска — пока
15
+ задача ещё в голове; шаги 4–6 принимают вернувшийся ответ одним ходом и возвращают исполнителя
16
+ к прежней работе.
11
17
 
12
18
  ## 1. Найди список загруженного
13
19
 
@@ -42,50 +48,61 @@ ls -t "${TMPDIR}claude-skill-gate/"*.loaded | head -5
42
48
  которой не было» — ровно то, из чего получаются правила. Приглаженная сводка даёт приглаженный
43
49
  разбор.
44
50
 
45
- ## 3. Запусти агента
51
+ ## 3. Запусти агента в фон и вернись к работе
46
52
 
47
53
  Инструментом `Agent`, `subagent_type: 'skill-curator'`. В промпт — путь к `.loaded` и сводку
48
54
  целиком.
49
55
 
50
- ## 4. Выгрузи предложения файлом
56
+ Ход на этом не кончается: пока агент работает, берётся следующая задача. Ответ придёт
57
+ уведомлением, и тогда идут шаги 4–6 — один ход, после которого исполнитель возвращается к тому,
58
+ что делал.
59
+
60
+ ## 4. Положи находки в папку задачи
51
61
 
52
- Ответ роли живёт в переписке и умирает вместе с ней, а правки в пакет идут из другого дерева и
53
- в другой день. Поэтому предложения ложатся на диск — их пишешь ты, не роль: файлов она не
54
- пишет вовсе.
62
+ Ответ роли живёт в переписке и умирает вместе с ней, поэтому он сразу ложится на диск рядом с
63
+ ходом работы, в папку задачи. Пишешь его ты, не роль: файлов она не пишет вовсе.
55
64
 
56
65
  ```bash
57
- mkdir -p .claude/rt-kit/proposals
58
- cp .claude/rt-kit/templates/proposal.md .claude/rt-kit/proposals/$(date +%F)-<ветка>.md
66
+ cat > docs/tasks/<ветка>/curator.md # заголовок блока — «## <адрес> · <ресурс>»
59
67
  ```
60
68
 
61
- Дальше по блоку на предложение, заголовком `## <адрес> · <ресурс>`. Адрес роль уже поставила,
62
- твоё дело — не потерять его и не переписать текст своими словами.
69
+ Адрес у каждого блока роль уже поставила «пакет», «компаньон» или «дерево». Твоё дело — не
70
+ потерять его и не переписать текст своими словами.
63
71
 
64
- Файл читает `agent-kit propose`: по заголовку он отбирает то, что уезжает в приём. Блок без
65
- адреса в заголовке не уедет никуда и останется лежать молча.
72
+ Папка задачи умирает со слиянием, а находки должны пережить весь эпик: владелец читает их
73
+ разом, когда эпик кончился. Поэтому при разборе папки файл находок не удаляется, а переезжает к
74
+ замыслу эпика — паттерн закрытия работы. Работа вне эпика показывает находки владельцу сразу.
66
75
 
67
- ## 5. Отправь то, что адресовано пакету
76
+ ## 5. Отправь сводку наблюдений и только её
68
77
 
69
78
  ```bash
70
79
  npx agent-kit propose --dry-run # что уехало бы
71
80
  npx agent-kit propose # отправить груз в приём
72
81
  ```
73
82
 
74
- Груз уезжает при каждом прогоне: сводка наблюдений со снимком надстроек, предложения с адресом
75
- «пакет» когда они есть,и разборы происшествий. Прогон без замечаний тоже говорит, чем
76
- пользовались, чем не пользовались ни разу и что дерево переопределило. Отправленное предложение
77
- помечается в том же файле и второй раз не уезжает.
83
+ Груз уезжает при каждом прогоне: сводка наблюдений со снимком надстроек, разборы происшествий и
84
+ предложения, лежащие в каталоге предложений. Сводка факт: чем пользовались, чем не
85
+ пользовались ни разу, что дерево переопределило. Она уезжает всегда и слова владельца не ждёт.
86
+
87
+ **Находки разбора в каталог предложений сами не ложатся, и потому не уезжают.** Предложение —
88
+ заготовка правки чужого дерева, и часть заготовок отпадает при первом же чтении; уехавшая без
89
+ разбора, она становится работой того, кто её не заказывал. В каталог предложений переносится
90
+ только то, что владелец назвал верным, — и тогда же уезжает.
78
91
 
79
92
  Отправка отказывает, если адрес этого дерева нашёлся в сводке или в тексте предложения — путь,
80
93
  имя корня, чужой репозиторий. Это не придирка: груз уезжает наружу целиком. Правь текст, а не
81
94
  обходи проверку. Разбор происшествия проверкой не накрыт: он по устройству называет файлы
82
95
  дерева, где промах случился.
83
96
 
84
- ## 6. Отдай результат владельцу
97
+ ## 6. Отдай находки владельцу — по концу эпика
98
+
99
+ Покажи находки **как есть**: роль пишет готовый текст для вставки, и пересказ его портит. По
100
+ каждой скажи своё — согласен или нет и почему; правило, с которым ты не согласен, вставлять не
101
+ надо.
85
102
 
86
- Покажи предложения агента **как есть**: он пишет готовый текст для вставки, и пересказ его
87
- портит. По каждому скажи своё согласен или нет и почему; правило, с которым ты не согласен,
88
- вставлять не надо.
103
+ Работа в эпике показывает их не сразу: находки копятся у замысла эпика и читаются разом, когда
104
+ эпик кончился,так владелец видит повторяющееся, а не разрозненные заметки. Названное им
105
+ верным переносится в каталог предложений и уезжает шагом 5.
89
106
 
90
107
  У каждого предложения агент ставит пометку «пакет», «компаньон» или «дерево»: тексты приезжают
91
108
  из `@rt-tools/agent-kit`, и правка разложенного файла на месте теряется на следующем
@@ -13,26 +13,27 @@
13
13
 
14
14
  ## Слой правил
15
15
 
16
- | Термин | Что это |
17
- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
- | Закон | Файл в каталоге конституции. Говорит, что должно быть верно, и не знает ни путей, ни имён файлов. Верен для любого приложения этого класса |
19
- | Законы приложения | Слой законов, верных только для этого приложения: деньги, локали, доступ. Предметность в них законна — она их предмет |
20
- | Правило | Скил с `kind: rule`. Привязывает закон к этому дереву: чем это здесь названо и где лежит |
21
- | Паттерн | Скил с `kind: pattern`. Готовый код и порядок действий; стоит при правиле |
22
- | Компаньон | Файл `implementation.md` рядом с правилом: имена и пути этого дерева. Пакет знает приём, но не знает имён — их пишет проект |
23
- | Спек | Описание домена: как он работает. Говорит об установившемся, а не о предстоящем |
24
- | Домен | Предмет, у которого свой спек. Выросший домен делится на поддомены, а не на соседние домены |
25
- | Сценарий | Наблюдаемое поведение под номером `SC-<ПРЕФИКС>-<НОМЕР>`. Номер стоит в заголовке теста |
26
- | Привязка | Строка `` `файл:символ` `` в компаньоне или в спутнике спека — место, где утверждение исполняется |
27
- | Спутник | Файл рядом со спеком или правилом: компаньон, перечень сценариев |
28
- | Договорённость о продукте | Как продукт себя поведёт, записанное до кода. Единственное место, где спек говорит о будущем; после выкатки вливается в спек домена, а директория удаляется |
29
- | Ресурс | Единица того, что везёт пакет правил: закон, правило, паттерн, гард, проверка, роль, команда, конвейер, шаблон, умолчание, документ |
30
- | Раскладка | Перенос ресурса из пакета в дерево по его роду и настройке слоя |
31
- | Разложенный файл | Файл в дереве с шапкой пакета. Правится не на месте, а надстройкой: правка на месте теряется на следующей раскладке |
32
- | Надстройка | Файл дерева, который сливается с разложенным по заголовкам разделов |
33
- | Наблюдение | Строка о событии слоя правил: правило загружено, гейт отбил, гард отказал. Пишет гард, живёт в дереве, наружу уезжает счётчиками. Журналом не называется |
34
- | Сводка | Что наблюдения говорят за отрезок дней: чем пользовались, чем ни разу, обо что спотыкались |
35
- | Предложение | Готовая формулировка правки правил с адресом: пакет, компаньон или дерево. Приносит разбор закрытой задачи, отправляет человек командой |
16
+ | Термин | Что это |
17
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
+ | Закон | Файл в каталоге конституции. Говорит, что должно быть верно, и не знает ни путей, ни имён файлов. Верен для любого приложения этого класса |
19
+ | Законы приложения | Слой законов, верных только для этого приложения: деньги, локали, доступ. Предметность в них законна — она их предмет |
20
+ | Правило | Скил с `kind: rule`. Привязывает закон к этому дереву: чем это здесь названо и где лежит |
21
+ | Паттерн | Скил с `kind: pattern`. Готовый код и порядок действий; стоит при правиле |
22
+ | Компаньон | Файл `implementation.md` рядом с правилом: имена и пути этого дерева. Пакет знает приём, но не знает имён — их пишет проект |
23
+ | Спек | Описание домена: как он работает. Говорит об установившемся, а не о предстоящем |
24
+ | Домен | Предмет, у которого свой спек. Выросший домен делится на поддомены, а не на соседние домены |
25
+ | Сценарий | Наблюдаемое поведение под номером `SC-<ПРЕФИКС>-<НОМЕР>`. Номер стоит в заголовке теста |
26
+ | Привязка | Строка `` `файл:символ` `` в компаньоне или в спутнике спека — место, где утверждение исполняется |
27
+ | Спутник | Файл рядом со спеком или правилом: компаньон, перечень сценариев |
28
+ | Договорённость о продукте | Как продукт себя поведёт, записанное до кода. Единственное место, где спек говорит о будущем; после выкатки вливается в спек домена, а директория удаляется |
29
+ | Ресурс | Единица того, что везёт пакет правил: закон, правило, паттерн, гард, проверка, роль, команда, конвейер, шаблон, умолчание, документ |
30
+ | Раскладка | Перенос ресурса из пакета в дерево по его роду и настройке слоя |
31
+ | Разложенный файл | Файл в дереве с шапкой пакета. Правится не на месте, а надстройкой: правка на месте теряется на следующей раскладке |
32
+ | Надстройка | Файл дерева, который сливается с разложенным по заголовкам разделов |
33
+ | Наблюдение | Строка о событии слоя правил: правило загружено, гейт отбил, гард отказал. Пишет гард, живёт в дереве, наружу уезжает счётчиками. Журналом не называется |
34
+ | Сводка | Что наблюдения говорят за отрезок дней: чем пользовались, чем ни разу, обо что спотыкались |
35
+ | Предложение | Готовая формулировка правки правил с адресом: пакет, компаньон или дерево. Приносит разбор закрытой задачи или слово посреди работы, отправляет человек командой |
36
+ | Слово | Реплика человека посреди работы о слое правил: что мешает, чего не хватило, что сработало не так. Ложится блоком в файл предложений, а не живёт до конца захода |
36
37
 
37
38
  ## Работа
38
39
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # rt-hook: PreToolUse Edit|Write|MultiEdit|mcp__webstorm__create_new_file
2
+ # rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
3
3
  # Требует: hooks/profile-check.sh
4
4
  # Гард «ничего не пишется с нуля». PreToolUse на правке кода и разметки.
5
5
  #
@@ -47,9 +47,23 @@ case "$tool" in
47
47
  # сменой не инструмента, а способа записи; текстом правки тогда служит сама команда, и
48
48
  # заведённое ею в heredoc читается наравне с телом правки. Разбор —
49
49
  # `2026-08-15-guard-denied-shell-wrote-anyway.md`.
50
- Bash)
50
+ #
51
+ # Терминал среды исполняет ту же командную строку и кладёт её в то же поле: без этих двух
52
+ # имён гард стоял бы объявленным на них и молча пропускал — состояние хуже необъявленного,
53
+ # потому что снаружи выглядит закрытым.
54
+ Bash | mcp__webstorm__execute_terminal_command | mcp__webstorm__execute_tool)
51
55
  shell_cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)"
52
56
  [ -z "$shell_cmd" ] && exit 0
57
+ # Универсальный исполнитель прячет настоящую команду во вложенной строке: без её разбора
58
+ # путь стоит за кавычкой, и до него не дотягивается ни один образец.
59
+ if [ "$tool" = "mcp__webstorm__execute_tool" ] && command -v perl >/dev/null 2>&1; then
60
+ inner="$(printf '%s' "$shell_cmd" | perl -0ne '
61
+ if (/--command(?:=|\s+)(?:"((?:[^"\\]|\\.)*)"|\x27([^\x27]*)\x27|(.+))/s) {
62
+ print defined $1 ? $1 : (defined $2 ? $2 : $3);
63
+ }
64
+ ' 2>/dev/null)"
65
+ [ -n "$inner" ] && shell_cmd="$inner"
66
+ fi
53
67
  ;;
54
68
  *) exit 0 ;;
55
69
  esac
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # rt-hook: PreToolUse Edit|Write|MultiEdit|Bash
2
+ # rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
3
3
  # Гейт правил: не даёт править файл, пока не загружено правило, под которое он подпадает.
4
4
  #
5
5
  # Закон и правило, которых никто не открывает, не действуют. Напоминание в подсказке помогает
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # rt-hook: PreToolUse Edit|Write|MultiEdit
2
+ # rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
3
3
  # Требует: hooks/profile-check.sh
4
4
  # PreToolUse guard for Edit|Write|MultiEdit: код не пишется раньше замысла.
5
5
  #
@@ -49,9 +49,23 @@ case "$tool" in
49
49
  # Второй ярус: та же правка, положенная командой оболочки. Без него отказ гарда обходится
50
50
  # сменой не инструмента, а способа записи — перенаправлением, `sed -i`, интерпретатором с
51
51
  # heredoc. Разбор — `2026-08-15-guard-denied-shell-wrote-anyway.md`.
52
- Bash)
52
+ #
53
+ # Терминал среды исполняет ту же командную строку и кладёт её в то же поле: без этих двух
54
+ # имён гард стоял бы объявленным на них и молча пропускал — состояние хуже необъявленного,
55
+ # потому что снаружи выглядит закрытым.
56
+ Bash | mcp__webstorm__execute_terminal_command | mcp__webstorm__execute_tool)
53
57
  cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)"
54
58
  [ -z "$cmd" ] && exit 0
59
+ # Универсальный исполнитель прячет настоящую команду во вложенной строке: без её разбора
60
+ # путь стоит за кавычкой, и до него не дотягивается ни один образец.
61
+ if [ "$tool" = "mcp__webstorm__execute_tool" ] && command -v perl >/dev/null 2>&1; then
62
+ inner="$(printf '%s' "$cmd" | perl -0ne '
63
+ if (/--command(?:=|\s+)(?:"((?:[^"\\]|\\.)*)"|\x27([^\x27]*)\x27|(.+))/s) {
64
+ print defined $1 ? $1 : (defined $2 ? $2 : $3);
65
+ }
66
+ ' 2>/dev/null)"
67
+ [ -n "$inner" ] && cmd="$inner"
68
+ fi
55
69
  rt_needs rt_shell_writes task-flow-guard || exit 0
56
70
  rt_needs rt_shell_paths task-flow-guard || exit 0
57
71
  rt_shell_writes "$cmd" || exit 0
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bash
2
+ # rt-hook: Stop
3
+ # Гард ожидания: ход, в котором открыт PR, не заканчивается, пока в нём не было ни одного
4
+ # действия по следующей задаче. Stop.
5
+ #
6
+ # Зачем именно так. Статья «ожидание прогона работой не занимают» держится памятью исполнителя, и
7
+ # держится плохо: образец сообщения владельцу кончается фразой о следующей задаче, а фраза
8
+ # исполняется как обещание — заход произносит её и кончает ход. Ход, в котором не сделано ничего,
9
+ # ничем себя не выдаёт: ни правкой файла, ни командой, — и промах виден только владельцу, только
10
+ # по тому, что работа не двигается, и только когда он спросит прямо.
11
+ #
12
+ # Признак берётся из хода, а не из сети. Спросить хостинг об открытых PR было бы точнее, но
13
+ # сетевой вызов на завершении хода падает вместе со связью и отбивал бы работу вместо промаха.
14
+ # Поэтому судится пара: в ходе был вызов открытия PR — и в том же ходе было действие по
15
+ # следующей задаче.
16
+ #
17
+ # Что считается действием: заведение задачи, заведение ветки, перевод колонки очереди работ,
18
+ # заведение папки задачи. Набор открыт и пополняется правкой — полнота его открытый вопрос, а не
19
+ # обещание.
20
+ #
21
+ # Чего гард не судит. Ход, в котором PR не открывали, — здесь он молчит: пустой ход неотличим
22
+ # от хода, которому нечего было делать. Это известная его граница.
23
+ #
24
+ # ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, нехватке `jq`, отсутствии записи хода и повторном
25
+ # заходе ход РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
26
+
27
+ input="$(cat 2>/dev/null)"
28
+ [ -z "$input" ] && exit 0
29
+
30
+ command -v jq >/dev/null 2>&1 || exit 0
31
+
32
+ # Повторный заход по тому же ходу не судится: гард сказал своё один раз и отпускает.
33
+ active="$(printf '%s' "$input" | jq -r '.stop_hook_active // false' 2>/dev/null)"
34
+ [ "$active" = "true" ] && exit 0
35
+
36
+ transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)"
37
+ [ -z "$transcript" ] && exit 0
38
+ [ -f "$transcript" ] || exit 0
39
+
40
+ # Открытие PR у каждого хостинга своё, и гард переносится между ними целиком: набор называет все
41
+ # три формы, а не ту, что стоит в этом дереве. Правка тела PR сюда не входит — она не открывает
42
+ # ничего.
43
+ opened_re='gh[^|;&]*pr[[:space:]]+create|api[^|;&]*-X[[:space:]]+POST[^|;&]*/pulls|glab[^|;&]*mr[[:space:]]+create|az[[:space:]]+repos[[:space:]]+pr[[:space:]]+create'
44
+
45
+ # Первое действие по следующей задаче. Заведение папки стоит здесь наравне с командами: работа
46
+ # по уже заведённому номеру начинается именно с неё.
47
+ moved_re='task:new|task:move|checkout[[:space:]]+-b|docs/tasks/'
48
+
49
+ # Ход — это всё, что записано после последнего настоящего ввода владельца. Ответ инструмента
50
+ # приходит той же ролью, поэтому строки с `tool_result` вводом не считаются.
51
+ #
52
+ # Хвост в 400 строк: запись хода растёт всю сессию, а судится только последний ход.
53
+ verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r --arg opened "$opened_re" --arg moved "$moved_re" '
54
+ def is_input:
55
+ .type == "user"
56
+ and (((.message.content // []) | if type == "array"
57
+ then ([.[] | select(.type == "tool_result")] | length)
58
+ else 0 end) == 0);
59
+
60
+ (map(is_input) | rindex(true)) as $i
61
+ | (if $i == null then [] else .[$i:] end) as $turn
62
+ | [$turn[] | select(.type == "assistant") | (.message.content // [])[] | select(.type == "tool_use")] as $uses
63
+ | ($uses | map((.input.command // "")) | join("\n")) as $ran
64
+ | ($ran | test($opened; "i")) as $opened_pr
65
+ | ($ran | test($moved; "i")) as $went_on
66
+ | if $opened_pr and ($went_on | not) then "owe" else "pass" end
67
+ ' 2>/dev/null)"
68
+
69
+ [ "$verdict" = "owe" ] || exit 0
70
+
71
+ reason="BLOCKED by waiting-turn-guard: в этом ходе открыт PR, а действия по следующей задаче в нём нет ни одного. Ожидание чужого шага заходом не занимают: прогон идёт на стороне и быстрее от взгляда на него не становится.
72
+
73
+ Сказать «беру следующую задачу» — не то же самое, что взять её: фраза живёт до конца хода, а работа не двигается, и заметить это может только владелец.
74
+
75
+ Тем же ходом делается первое действие по следующей задаче — заведение задачи, ветки или папки:
76
+
77
+ npm run task:new -- --title '<Что не так>' --slug <slug>
78
+ git checkout -b <КЛЮЧ>-<номер>-<slug>
79
+
80
+ Конец прогона узнаётся возвратом фоновой команды, а не взглядом на страницу.
81
+
82
+ Гард судит один ход: следующий заход не отбивается."
83
+
84
+ jq -n --arg r "$reason" '{decision:"block",reason:$r}' 2>/dev/null \
85
+ || printf '{"decision":"block","reason":"waiting-turn-guard: PR открыт — тем же ходом берётся следующая задача."}\n'
86
+
87
+ exit 0
@@ -10,6 +10,18 @@
10
10
  очередь не попала, никто не видит, и работа за ней не планировалась.
11
11
  - **Правка попадает в главную ветку только через отдельную ветку.** Прямая запись в главную
12
12
  лишает правку и обсуждения, и возможности откатить её одним движением.
13
+ - **В очереди работ стоят задачи, а не PR о них.** У задачи и её PR один номер и одна судьба,
14
+ поэтому вторая карточка о той же работе ничего не добавляет — она удваивает очередь и врёт о
15
+ её длине. Читают очередь затем, чтобы увидеть, что сделано и что осталось; PR отвечает на
16
+ другой вопрос — как именно сделано, — и попадают в него из карточки задачи, где связь с ним
17
+ и так стоит. Карточка PR при этом живёт своей жизнью: закрывается позже задачи, висит в
18
+ очереди после слияния и остаётся в ней навсегда, потому что колонки под неё нет.
19
+ - **Проверка не гоняет того, что правка не может сломать.** Набор, одинаковый для любой правки,
20
+ выглядит строгим, а работает наоборот: прогон, который длится вдесятеро дольше нужного, учат
21
+ не ждать, а обходить. Состав набора выводится из состава правки — из того, что она задела, а
22
+ не из того, кем она названа; правка, не тронувшая ни строки кода, не собирает образов и не
23
+ снимает кадров. Пропущенное при этом называется пропущенным: молча выпавший шаг читается как
24
+ пройденный.
13
25
  - **У задачи одна ветка, у ветки одна задача.** Откат снимает всё, что въехало этой веткой,
14
26
  разом: две задачи в ней откатятся только вместе, а задача, въехавшая двумя ветками, после
15
27
  отката одной останется наполовину сделанной — и в очереди работ этого не видно. Работа,
@@ -71,6 +83,22 @@
71
83
  иначе «сошлось» значит в этих двух местах разное.
72
84
  - **Документ едет вместе с правкой, которую он описывает.** Ни сборка, ни проверки текстов
73
85
  не читают, поэтому расхождение копится молча и потом выглядит действующей справкой.
86
+ - **Работа, меняющая код, кончается открытым PR.** PR — единственное место, где человек видит
87
+ правку целиком, отвечает на неё и вливает её; коммит в ветке и запушенная ветка этого места
88
+ не заменяют. Пока PR не открыт, работа сделанной не считается, сколько бы её ни было в
89
+ истории ветки: разбор по ней невозможен, а человек о ней не знает. Открывается PR тем же
90
+ ходом, которым исполнитель говорит, что работу отдаёт, — а не следующим заходом и не по
91
+ напоминанию.
92
+ - **PR, не готовый к слиянию, помечается черновиком.** Открытый PR читается как приглашение
93
+ влить, и человек нажимает слияние, не спрашивая, кончилась ли работа. Черновик разводит два
94
+ состояния, которые иначе выглядят одинаково: правка выложена на обозрение — и правка готова
95
+ поехать в главную ветку. Помечается им всё, что ждёт прогона, доработки или ответа на
96
+ вопрос; вопрос при этом задаётся в самом PR, а не остаётся в голове исполнителя.
97
+ - **Снятие черновика — отдельный ход, и им исполнитель отвечает за готовность.** Черновик
98
+ снимается тогда, когда проверки пройдены, доработок не осталось и работа сходится с тем,
99
+ ради чего заводилась задача. Пока он стоит, молчание исполнителя значит «ещё не готово», и
100
+ человек ничего не должен переспрашивать; после снятия оно значит «можно вливать», и цена
101
+ ошибки здесь — правка в главной ветке.
74
102
  - **PR о сделанном остаётся верным до самого слияния.** Он описывает дерево на день, когда
75
103
  его написали, а разбора ждёт днями: за это время главная ветка вливается в ветку, и
76
104
  утверждение PR о соседних файлах становится неправдой молча — тел PR не читает ни
@@ -77,3 +77,21 @@
77
77
  - **Работа, которая переносит решения, называет для каждого, куда оно ушло.** Иначе по
78
78
  описанию прошлого не отличить решение, ставшее правилом, от решения, потерянного при
79
79
  переносе: оба выглядят одинаково — записью, на которую никто не ссылается.
80
+ - **Текст, раздаваемый наружу, судится не слабее своей копии у потребителя.** Требование,
81
+ стоящее к копии и не стоящее к источнику, находит промах у того, кто его не делал и починить
82
+ не может: до потребителя промах доезжает целым, а краснеет уже там.
83
+ - **Редакция текста, которую это дерево не выбрало, судится наравне с выбранной.**
84
+ Непрочитанная редакция расходится с прочитанной молча, и узнаёт об этом первый, кто её
85
+ выберет, — то есть тот, у кого нет ни истории расхождения, ни повода его искать.
86
+ - **Набор обязательных разделов объявлен отдельно, и образец ему не хозяин.** Образец —
87
+ черновик для того, кто заводит текст, и стареет он первым. Набор, выведенный из образца, либо
88
+ объявляет расхождением весь корпус разом, либо не замечает ничего.
89
+ - **Требование, которого никто не формулировал, молчит, а не отказывает.** Отказ на предмете
90
+ без объявленного требования гасят списком исключений, а список исключений через месяц
91
+ становится рабочим путём — и гасит вместе с шумом то, ради чего проверка заводилась.
92
+ - **Два текста об одном либо говорят одно, либо один из них неправ.** Согласие текстов между
93
+ собой не следует ни из целостности ссылок, ни из полноты разделов: оба проходят любую такую
94
+ проверку, а исполнитель берёт тот, который прочитал раньше. Ищется это чтением — считать
95
+ здесь нечего.
96
+ - **Изображение правится тем же изменением, что и текст, который оно изображает.** Разойдясь,
97
+ схема и проза остаются читаемыми обе, и первым это замечает тот, кто пошёл по схеме.
@@ -136,6 +136,22 @@
136
136
  - **Работа, отданная на разбор, освобождает исполнителя, а не останавливает его.** Отданное на
137
137
  разбор ждёт владельца, а не машину: следующая задача эпика берётся тем же движением, которым
138
138
  предыдущая ушла на разбор.
139
+ - **Ожидание машины работой не занимают.** Проверка, идущая на стороне, не спрашивает
140
+ исполнителя ни о чём и не идёт быстрее оттого, что он на неё смотрит. Пока она идёт, работа
141
+ продолжается: берётся следующая задача, а к проверке возвращаются тем ходом, которым читают
142
+ её конец. Заход, проведённый в ожидании, стоит ровно столько же, сколько заход, в котором
143
+ сделана задача, — и не даёт ничего.
144
+ - **Ожидание, которое всё-таки останавливает работу, называется владельцу отдельно и прямо.**
145
+ Есть случаи, где дальше и вправду не пройти: следующая задача стоит на неразобранной, или
146
+ правка ждёт решения, которого нет ни у кого, кроме владельца. Тогда исполнитель говорит три
147
+ вещи — что именно стоит, чего оно ждёт и что владелец может с этим сделать: разобрать работу
148
+ первой или снять ожидание своим словом. Сказанное вперемешку с отчётом о сделанном не
149
+ читается: остановка называется отдельно от всего остального.
150
+ - **Разбор закрытой работы идёт своим ходом и работу не задерживает.** Он смотрит на то, что
151
+ видно только заходу, который работу вёл, поэтому пропустить его нельзя; но и держать ради
152
+ него следующую задачу незачем — он ничего не спрашивает у исполнителя, пока идёт. Его находки
153
+ записываются туда, где их найдут после слияния работы, и показываются владельцу целиком, а не
154
+ уезжают наружу сами: что из них станет правкой, решает он.
139
155
  - **Отдав работу на разбор, исполнитель называет, чего ждёт и что сделает следом.** Владелец
140
156
  видит не голову исполнителя, а страницу работы: зелёная проверка и доступное действие
141
157
  читаются как «всё кончено». Названное вслух ожидание — единственное, что отличает «жду
@@ -2,7 +2,7 @@
2
2
  name: git-workflow-commit
3
3
  kind: pattern
4
4
  rule: git-workflow
5
- description: Паттерн правила git-workflow для дерева в Azure DevOps. Брать на заведение рабочего элемента, ветки, коммит, пуш и создание PR — заведение элемента со всеми шагами, перевод по состояниям, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, привязка PR к элементу, ревьювер, исполнитель и метки, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
5
+ description: Паттерн правила git-workflow для дерева в Azure DevOps. Брать на заведение рабочего элемента, ветки, коммит, пуш и создание PR — заведение элемента со всеми шагами, перевод по состояниям, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, привязка PR к элементу, ревьювер, исполнитель и метки, образец тела PR с разделом об оставшемся шаге, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
6
6
  ---
7
7
 
8
8
  # Ветка, коммит и PR
@@ -169,6 +169,35 @@ PR [86] Письмо владельцу с незаполненным ад
169
169
  Тип и область — `fix(site):`, `docs(common):` — в заголовок PR не идут: это формат заголовка
170
170
  коммита, и там его сверяет `commitlint`.
171
171
 
172
+ ## Не готовое к слиянию открывается черновиком
173
+
174
+ Правка кода отдаётся человеку открытым PR: запушенная ветка ему не показывается нигде. Открытый
175
+ PR при этом читается как приглашение влить, поэтому у незаконченной работы он открывается
176
+ черновиком — завершение у черновика хостинг блокирует сам:
177
+
178
+ ```bash
179
+ AZURE_DEVOPS_EXT_PAT="$TOKEN" az repos pr create --draft true --title '[<КЛЮЧ>-86] …' \
180
+ --description "$(cat тело.md)"
181
+ ```
182
+
183
+ Конвейер проверок у черновика по умолчанию не запускается: молчание прогона за зелёный прогон
184
+ не принимается, и набор гоняется на своей машине либо запуском вручную.
185
+
186
+ Черновиком идёт всё, что ждёт прогона конвейера, доработки или ответа на вопрос. Вопрос
187
+ задаётся в самом PR, а не остаётся в голове исполнителя: человек читает PR, а не переписку
188
+ захода.
189
+
190
+ Снимается черновик отдельным вызовом, и это тот самый ход, которым исполнитель говорит, что
191
+ решение готово:
192
+
193
+ ```bash
194
+ AZURE_DEVOPS_EXT_PAT="$TOKEN" az repos pr update --id 86 --draft false
195
+ ```
196
+
197
+ До снятия молчание исполнителя значит «ещё не готово», после — «можно вливать». Снятие
198
+ черновика и просьба влить идут одним ходом: снятый черновик, о котором человеку не сказали,
199
+ ждёт разбора ровно так же, как не снятый.
200
+
172
201
  ## PR привязывается к элементу при создании
173
202
 
174
203
  Привязка задаётся флагом, а не правкой после: у токена может не быть права править чужой
@@ -197,6 +226,46 @@ az repos pr update --id 205 --description "$(cat тело.md)"
197
226
  Правка описания переписывает его целиком. Тело перечитывается всякий раз, когда в ветку что-то
198
227
  влилось после публикации: PR утверждает про дерево, а дерево с тех пор изменилось.
199
228
 
229
+ ## Образец тела PR
230
+
231
+ Четыре раздела, и порядок между ними один: строка связи, что сделано, чем подтверждено,
232
+ оставшийся шаг. Раздел, которому нечего сказать, пишется словами — пустой заголовок и снятый
233
+ заголовок читаются одинаково, а значат разное.
234
+
235
+ ```markdown
236
+ Закрывает рабочий элемент 86.
237
+
238
+ ## Что сделано
239
+
240
+ - <правка, названная тем, что она меняет для читателя, а не тем, какие файлы задела>
241
+
242
+ ## Чем подтверждено
243
+
244
+ - <проверка>: <её вывод одной строкой>
245
+ - Не гонялось: <что в набор не вошло и почему>
246
+
247
+ ## Оставшийся шаг
248
+
249
+ После одобрения ветка получает ещё один коммит — разбор папки задачи, — и только потом
250
+ вливается. До этого коммита вливать рано: папка уедет в главную ветку неразобранной.
251
+ ```
252
+
253
+ Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
254
+ — в тот ход, которым папка разбирается и снимается черновик:
255
+
256
+ ```markdown
257
+ ## Оставшийся шаг
258
+
259
+ Не осталось: папка задачи разобрана коммитом `<sha>`, черновик снят. Можно вливать.
260
+ ```
261
+
262
+ Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
263
+ сказанное владельцу вслух живёт до следующей реплики, а тело лежит у самой кнопки. Одно другого
264
+ не отменяет — порядок обоих сообщений владельцу описывает паттерн закрытия работы.
265
+
266
+ Проверить тело машиной нечем: ни одна сверка его не читает, а хостинг спрашивает только про
267
+ заголовок. Держится образец тем, кто пишет тело, — как и слова вслух.
268
+
200
269
  ## Состояние PR читается, а не додумывается
201
270
 
202
271
  Команды правки отвечают нулевым кодом и тогда, когда ничего не сделали. Поэтому после них PR
@@ -244,7 +313,10 @@ npm run task:move -- 86 in-review
244
313
  `browser-verification-measure`.
245
314
  9. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** —
246
315
  паттерн `seo-verify`.
247
- 10. **PR привязан к рабочему элементу**, ревьювер и исполнитель стоят.
316
+ 10. **PR привязан к рабочему элементу**, ревьювер и исполнитель стоят, а тело собрано по
317
+ образцу — разделы «Что сделано», «Чем подтверждено» и «Оставшийся шаг». Раздел оставшегося
318
+ шага к этому моменту говорит, что шагов не осталось: черновик снимается после разбора
319
+ папки, а не до него.
248
320
  11. **Заголовок PR несёт номер элемента и называет работу сделанной:** `[<номер>] <Что
249
321
  сделано>`, тем же номером, что стоит у элемента и в имени ветки.
250
322
  12. **Очередь работ сходится** — `npm run check:board`.