@rt-tools/agent-kit 0.12.0 → 0.14.0

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 (53) hide show
  1. package/assets/checks/board-runs.github.mjs +132 -0
  2. package/assets/checks/board.github.mjs +43 -41
  3. package/assets/checks/check-board.github.mjs +73 -8
  4. package/assets/checks/check-schema-drift.mjs +28 -5
  5. package/assets/checks/rt-kit-checks.config.mjs +12 -0
  6. package/assets/checks/task-new.github.mjs +15 -3
  7. package/assets/commands/feedback.md +8 -0
  8. package/assets/defaults/project.sh +50 -5
  9. package/assets/hooks/browser-guard-no-other-drivers.sh +1 -1
  10. package/assets/hooks/claim-guard.sh +34 -0
  11. package/assets/hooks/dev-server-guard.sh +1 -1
  12. package/assets/hooks/dispatch.sh +48 -15
  13. package/assets/hooks/git-guard-delivery-folder.sh +99 -0
  14. package/assets/hooks/git-guard-delivery-signature.sh +10 -4
  15. package/assets/hooks/git-guard-delivery.sh +21 -69
  16. package/assets/hooks/git-guard-push-tests.sh +2 -2
  17. package/assets/hooks/hook-input.sh +62 -0
  18. package/assets/hooks/override-write-guard.sh +107 -0
  19. package/assets/hooks/rerun-guard.sh +1 -1
  20. package/assets/hooks/rule-source-guard.sh +126 -0
  21. package/assets/hooks/task-flow-guard.sh +18 -0
  22. package/assets/hooks/turn-exit-guard.sh +33 -1
  23. package/assets/hooks/waiting-turn-guard.sh +39 -3
  24. package/assets/patterns/git-workflow-pr.azure.md +4 -4
  25. package/assets/patterns/git-workflow-pr.github.md +4 -4
  26. package/assets/patterns/git-workflow-pr.gitlab.md +4 -4
  27. package/assets/patterns/task-flow-archive.md +23 -21
  28. package/assets/patterns/task-flow-close.md +98 -96
  29. package/assets/patterns/task-flow-resume.md +5 -3
  30. package/assets/pitfalls/agent-kit.md +80 -0
  31. package/assets/pitfalls/git-workflow.github.md +8 -0
  32. package/assets/rules/deploy-flow.azure.md +15 -7
  33. package/assets/rules/deploy-flow.github.md +15 -6
  34. package/assets/rules/deploy-flow.gitlab.md +15 -7
  35. package/assets/rules/git-workflow.github.md +10 -5
  36. package/assets/rules/task-flow.md +44 -26
  37. package/assets/rules/turn-conduct.md +33 -0
  38. package/assets/skills/agent-kit.md +32 -77
  39. package/assets/templates/proposal.md +16 -1
  40. package/lib/proposals.d.ts +5 -1
  41. package/lib/proposals.d.ts.map +1 -1
  42. package/lib/proposals.js +74 -5
  43. package/lib/proposals.js.map +1 -1
  44. package/lib/shipment.d.ts.map +1 -1
  45. package/lib/shipment.fixture.d.ts +39 -0
  46. package/lib/shipment.fixture.d.ts.map +1 -0
  47. package/lib/shipment.fixture.js +99 -0
  48. package/lib/shipment.fixture.js.map +1 -0
  49. package/lib/shipment.js +59 -7
  50. package/lib/shipment.js.map +1 -1
  51. package/package.json +1 -1
  52. package/rt-tools-agent-kit-0.14.0.tgz +0 -0
  53. package/rt-tools-agent-kit-0.12.0.tgz +0 -0
@@ -49,7 +49,7 @@ done
49
49
 
50
50
  # Вызов перезапуска: слово перезапуска отдельным словом рядом со словом прогона.
51
51
  host_cli="${RT_HOST_CLI:-gh}"
52
- printf '%s' "$cmd" | grep -qE "(^|[;&|(]|&&|\|\|)[[:space:]]*${host_cli}([[:space:]]|$)" || exit 0
52
+ printf '%s' "$cmd" | grep -qE "${RT_CMD_BOUND}${host_cli}([[:space:]]|\$)" || exit 0
53
53
  printf '%s' "$cmd" | grep -qE '(^|[[:space:]])(run|workflow)([[:space:]]|$)' || exit 0
54
54
  printf '%s' "$cmd" | grep -qE '(^|[[:space:]])rerun([[:space:]]|$)' || exit 0
55
55
 
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env bash
2
+ # rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
3
+ # Требует: hooks/profile-check.sh, hooks/deny-tail.sh
4
+ # Гард места правки: слой правил чинится там, где сломано, а не там, где виден.
5
+ #
6
+ # Слой правил правит тот же исполнитель, которым слой правил управляет, и разницы между
7
+ # «исполняю правило» и «правлю правило» в дереве не видно ничем: разложенная копия лежит рядом
8
+ # с обычными файлами и правится так же. Правка доходит до диска и не доходит до места, где
9
+ # промах чинится: в дереве она видна, в пакете её нет, а через месяц раскладка отказывает по
10
+ # правленому файлу целиком — и цену платит тот, кто в этот день правил соседний ресурс.
11
+ #
12
+ # Знал об этом только `sync --check`, и говорил он на следующей раскладке, то есть в чужой
13
+ # ветке и чужим ходом. Гард говорит в минуту правки и называет адрес: источник пакета, если
14
+ # дерево его держит, иначе — надстройку.
15
+ #
16
+ # ЧТО СУДИТСЯ. Файл, который правят, несёт шапку раскладки: `rt-kit v<версия> · <ресурс> ·
17
+ # <дайджест>`. Ресурс из неё и есть адрес: `<источники>/<ресурс>` в дереве пакета,
18
+ # `.claude/rt-kit/overrides/<ресурс>` у потребителя.
19
+ #
20
+ # ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет `jq`, битый ввод, чужой инструмент, файла нет, шапки в нём нет,
21
+ # не git-репозиторий — правка РАЗРЕШАЕТСЯ. Сломанный гард не имеет права заклинить работу.
22
+
23
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
24
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hook-input.sh" 2>/dev/null || true
25
+
26
+ rt_hook_read
27
+ input="$RT_HOOK_INPUT"
28
+ [ -z "$input" ] && exit 0
29
+ command -v jq >/dev/null 2>&1 || exit 0
30
+
31
+ rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
32
+ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../defaults/project.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/defaults/project.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/project.sh"; do
33
+ # shellcheck disable=SC1090
34
+ [ -f "$profile" ] && . "$profile" 2>/dev/null
35
+ done
36
+
37
+ # shellcheck disable=SC1090
38
+ [ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
39
+ command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
40
+
41
+ # shellcheck disable=SC1090
42
+ [ -f "$rt_hooks_dir/deny-tail.sh" ] && . "$rt_hooks_dir/deny-tail.sh" 2>/dev/null
43
+ command -v rt_deny_tail >/dev/null 2>&1 || rt_deny_tail() { printf ''; }
44
+
45
+ deny() {
46
+ # shellcheck disable=SC1090
47
+ [ -f "$rt_hooks_dir/observe.sh" ] && . "$rt_hooks_dir/observe.sh" 2>/dev/null
48
+ command -v rt_note >/dev/null 2>&1 && rt_note guard-deny res=rule-source-guard
49
+
50
+ reason="$1 $(rt_deny_tail "$2")"
51
+ jq -n --arg r "$reason" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}' 2>/dev/null \
52
+ || printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Гард места правки."}}\n'
53
+ exit 0
54
+ }
55
+
56
+ # Цели записи, названные командой прямо. Печатает по одной в строке.
57
+ rt_write_targets() {
58
+ tr "\"'\`" ' ' \
59
+ | sed -E 's/>>?/\n>/g' \
60
+ | sed -nE '
61
+ s/^>[[:space:]]*([^[:space:]|&;]+).*/\1/p
62
+ s/(^|.*[[:space:]])tee[[:space:]]+(-a[[:space:]]+)?([^[:space:]|&;]+).*/\3/p
63
+ s/(^|.*[[:space:]])sed[[:space:]]+-i[[:space:]]+([^[:space:]]+[[:space:]]+)*([^[:space:]|&;]+)$/\3/p
64
+ s/(^|.*[[:space:]])(cp|mv|install)[[:space:]]+([^[:space:]]+[[:space:]]+)+([^[:space:]|&;]+).*/\4/p
65
+ ' \
66
+ | sort -u
67
+ }
68
+
69
+ tool="$(rt_hook_tool)"
70
+ candidates=""
71
+ case "$tool" in
72
+ Edit | Write | MultiEdit | mcp__webstorm__create_new_file)
73
+ candidates="$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.pathInProject // empty' 2>/dev/null)"
74
+ ;;
75
+ Bash | mcp__webstorm__execute_terminal_command | mcp__webstorm__execute_tool)
76
+ cmd="$(rt_hook_cmd)"
77
+ [ -z "$cmd" ] && exit 0
78
+ # Здесь берётся не общий признак записи, а цель, названная в команде прямо:
79
+ # перенаправление, `tee`, правка на месте, копирование поверх. Общий признак широк
80
+ # намеренно — в нём и имя интерпретатора, — и запуск разложенной проверки читался бы
81
+ # как правка её самой. Отбитие на чтении стоит дороже пропуска: гард, мешающий читать,
82
+ # выключают в первый же день.
83
+ #
84
+ # Снятие копии сюда не входит намеренно: снятый файл раскладка кладёт заново, и так
85
+ # чинят копию, которую переписал форматтер.
86
+ candidates="$(printf '%s' "$cmd" | rt_write_targets)"
87
+ ;;
88
+ *) exit 0 ;;
89
+ esac
90
+ [ -z "$candidates" ] && exit 0
91
+
92
+ root="${CLAUDE_PROJECT_DIR:-.}"
93
+
94
+ # Каталог источников пакета в этом дереве. Есть он только у дерева, которое пакет и везёт; у
95
+ # потребителя источника нет вовсе, и адрес правки у него один — надстройка.
96
+ sources=""
97
+ if rt_needs rt_kit_sources_dir rule-source-guard; then
98
+ sources="$(rt_kit_sources_dir 2>/dev/null)"
99
+ fi
100
+
101
+ while IFS= read -r candidate; do
102
+ [ -z "$candidate" ] && continue
103
+ case "$candidate" in
104
+ /*) ;;
105
+ *) candidate="$root/$candidate" ;;
106
+ esac
107
+ [ -f "$candidate" ] || continue
108
+
109
+ # Шапка стоит в начале файла, но не первой строкой: у сценария её отодвигает `#!`, у
110
+ # правила — заголовок с именем и родом ресурса. Десяти строк хватает обоим, а читать файл
111
+ # целиком нельзя: гард стоит на каждой правке.
112
+ resource="$(head -12 "$candidate" 2>/dev/null | sed -nE 's/.*rt-kit v[^ ]+ · ([^ ]+) · [0-9a-f]+.*/\1/p' | head -1)"
113
+ [ -z "$resource" ] && continue
114
+
115
+ if [ -n "$sources" ] && [ -f "$root/$sources/$resource" ]; then
116
+ deny "BLOCKED by rule-source-guard: «${candidate#"$root"/}» разложен пакетом, и правка на его месте теряется на следующей раскладке — а до тех пор раскладка отказывает по этому файлу целиком, и цену платит тот, кто в этот день правит соседний ресурс. Ресурс — «${resource}». Правь источник: ${sources}/${resource} — потом собери пакет и разложи." \
117
+ "правка, верная только этому дереву, идёт в надстройку .claude/rt-kit/overrides/${resource} — она сливается по разделу «## » и раскладку переживает"
118
+ fi
119
+
120
+ deny "BLOCKED by rule-source-guard: «${candidate#"$root"/}» разложен пакетом @rt-tools/agent-kit, и правка на его месте теряется на следующей раскладке. Ресурс — «${resource}». Правь надстройку: .claude/rt-kit/overrides/${resource} — она сливается по разделу «## » и раскладку переживает." \
121
+ "то, что верно любому дереву, правится в самом пакете и приезжает сюда новой редакцией"
122
+ done <<EOF
123
+ $candidates
124
+ EOF
125
+
126
+ exit 0
@@ -110,6 +110,7 @@ EOF
110
110
 
111
111
  # Каталог папок задач: у дерева он свой, но имя обычно общее.
112
112
  tasks_dir="${RT_TASKS_DIR:-docs/tasks}"
113
+ main_branch="${RT_MAIN_BRANCH:-main}"
113
114
 
114
115
  # Общий хвост отказа: два законных хода и законная форма обхода, если она у отказа есть. Файл
115
116
  # может быть не разложен — тогда хвоста нет, а причина отказа остаётся прежней.
@@ -146,6 +147,23 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)"
146
147
  dir="$root/$tasks_dir/$branch"
147
148
  plan="$dir/plan.md"
148
149
 
150
+ # Папка, разобранная коммитом этой ветки, — признак того, что работа отдана. Замысел с диска к
151
+ # этой минуте снят намеренно: уборка стоит до открытия заявки, потому что кнопку слияния
152
+ # нажимает человек на хостинге и закрывающему коммиту места после одобрения не остаётся.
153
+ # Правка после уборки — это правка по замечаниям разбора, и требовать под неё замысла значило
154
+ # бы запирать ветку собственным порядком. Признак берётся из истории ветки, а не с диска:
155
+ # снесённая, но не закоммиченная папка отданной работы не означает.
156
+ folder_archived() {
157
+ [ -n "$(git ls-tree -d --name-only HEAD -- "$tasks_dir/$branch" 2>/dev/null | head -1)" ] && return 1
158
+ base="$(git merge-base "$main_branch" HEAD 2>/dev/null)"
159
+ [ -z "$base" ] && return 1
160
+ had="$(git ls-tree -d --name-only "$base" -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
161
+ [ -z "$had" ] && had="$(git log "$base..HEAD" --diff-filter=A --name-only --pretty=format: -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
162
+ [ -n "$had" ]
163
+ }
164
+
165
+ folder_archived && exit 0
166
+
149
167
  if [ ! -f "$plan" ]; then
150
168
  deny "BLOCKED by task-flow: нет замысла — '${tasks_dir}/${branch}/plan.md'. Собери папку задачи с образца (cp -r ${tasks_dir}/_template ${tasks_dir}/${branch}) и заполни шапку, след задачи и этапы, затем повтори. Правило — скил task-flow."
151
169
  fi
@@ -74,6 +74,30 @@ case "$state" in
74
74
  работа-отдана | влито) exit 0 ;;
75
75
  esac
76
76
 
77
+ # То же самое, но объявить это на диске уже нечем: папка задачи разбирается до открытия заявки,
78
+ # и ход работы уезжает вместе с ней. Признак берётся из истории ветки — папка, снятая её
79
+ # коммитом.
80
+ #
81
+ # Отпускать по нему ход нельзя: папка снимается ДО заявки, и между этими двумя движениями работа
82
+ # не отдана никому. Ход, попавший в зазор, прежде выходил отсюда нулём — а до отдачи ему
83
+ # оставался ровно один шаг, и он его не сделал. Признак поэтому только снимает требование
84
+ # состояния: дальше ход судится вторым признаком, как всякий другой. Ход, в котором заявку
85
+ # открыли или прочитали, второй признак пропускает сам — вызов клиента хостинга он считает
86
+ # работой.
87
+ folder_archived() {
88
+ [ -n "$branch" ] || return 1
89
+ [ -n "$(git ls-tree -d --name-only HEAD -- "$tasks_dir/$branch" 2>/dev/null | head -1)" ] && return 1
90
+ main_branch="${RT_MAIN_BRANCH:-main}"
91
+ base="$(git merge-base "$main_branch" HEAD 2>/dev/null)"
92
+ [ -z "$base" ] && return 1
93
+ had="$(git ls-tree -d --name-only "$base" -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
94
+ [ -z "$had" ] && had="$(git log "$base..HEAD" --diff-filter=A --name-only --pretty=format: -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
95
+ [ -n "$had" ]
96
+ }
97
+
98
+ archived=false
99
+ [ -z "$progress" ] && folder_archived && archived=true
100
+
77
101
  # Следующий шаг из хода работы — его страж и называет в отказе: исполнитель, которому сказано
78
102
  # только «работа не кончена», перечитывает ту же строку сам.
79
103
  next_step=""
@@ -177,7 +201,15 @@ fi
177
201
 
178
202
  [ "$worked" = "true" ] && exit 0
179
203
 
180
- if [ -z "$state" ]; then
204
+ if [ "$archived" = "true" ]; then
205
+ reason="BLOCKED by turn-exit-guard: папка задачи снята коммитом ветки, а за этот ход не сделано ничего — ни правки, ни команды, меняющей дерево.
206
+
207
+ Снятая папка означает середину отдачи, а не её конец: убирают её ДО того, как открыта заявка, и между этими двумя движениями работу не видит никто, кроме того, кто её сделал. Состояние работы с этой минуты объявить нечем, поэтому ход судится по второму признаку — была ли за него работа.
208
+
209
+ Оставшийся шаг один: открыть заявку черновиком. Заявка уже открыта — возьми следующую задачу: ожидание чужого прогона работой не является и ходом не кончается.
210
+
211
+ Страж судит один ход: следующий заход не отбивается."
212
+ elif [ -z "$state" ]; then
181
213
  reason="BLOCKED by turn-exit-guard: за этот ход не сделано ничего — ни правки, ни команды, меняющей дерево. Папки задачи у этой работы нет, и состояние взять неоткуда, но ход это не кончает.
182
214
 
183
215
  Ход кончается четырьмя способами, и других нет: вопрос владельцу, ответа на который в правилах нет; отказ гарда; заполненное окно захода; отданная работа с начатой следующей. Названная и не запущенная команда выходом не является: строка «сейчас запущу» — объявление намерения, а оно прямо названо ложным концом хода.
@@ -63,12 +63,19 @@ red_re='completed[[:space:]]+failure|"conclusion"[[:space:]]*:[[:space:]]*"failu
63
63
  # по следующей задаче не считается — она чинит прежнюю, а не двигает работу дальше.
64
64
  moved_re='task:new|task:move|checkout[[:space:]]+-b|docs/tasks/'
65
65
 
66
+ # Чем ход показывает, что отданную работу он довёл до конца, а не бросил черновиком. Снятие
67
+ # черновика — очевидный случай; чтение прогона — тот, где снимать ещё нечего, но исполнитель
68
+ # посмотрел, а не сказал «жду». Две готовые заявки простояли черновиками именно потому, что
69
+ # следующая задача была взята вместо этого, а не сверх этого.
70
+ ready_re='pr[[:space:]]+ready|run[[:space:]]+(list|view|watch)|pr[[:space:]]+checks|check-runs|check:board|board\.mjs'
71
+
66
72
  # Ход — это всё, что записано после последнего настоящего ввода владельца. Ответ инструмента
67
73
  # приходит той же ролью, поэтому строки с `tool_result` вводом не считаются.
68
74
  #
69
75
  # Хвост в 400 строк: запись хода растёт всю сессию, а судится только последний ход.
70
76
  verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r \
71
- --arg opened "$opened_re" --arg moved "$moved_re" --arg read "$read_re" --arg red "$red_re" '
77
+ --arg opened "$opened_re" --arg moved "$moved_re" --arg read "$read_re" --arg red "$red_re" \
78
+ --arg ready "$ready_re" '
72
79
  def is_input:
73
80
  .type == "user"
74
81
  and (((.message.content // []) | if type == "array"
@@ -90,12 +97,41 @@ verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r \
90
97
  | ($ran | test($opened; "i")) as $opened_pr
91
98
  | (($ran | test($read; "i")) and ($out | test($red; "i"))) as $red_run
92
99
  | ($ran | test($moved; "i")) as $went_on
93
- | if $went_on then "pass"
94
- elif $opened_pr then "owe:pr"
100
+ | ($ran | test($ready; "i")) as $checked
101
+ | if $opened_pr and ($went_on | not) then "owe:pr"
102
+ elif $opened_pr and ($checked | not) then "owe:draft"
103
+ elif $went_on then "pass"
95
104
  elif $red_run then "owe:run"
96
105
  else "pass" end
97
106
  ' 2>/dev/null)"
98
107
 
108
+ # Черновик, оставленный при взятой следующей задаче, — отдельный отказ: там требование не про
109
+ # следующую задачу, а про доведение отданной.
110
+ if [ "$verdict" = "owe:draft" ]; then
111
+ reason="BLOCKED by waiting-turn-guard: в этом ходе открыт PR, следующая задача взята, а состояние отданной работы не спрошено ни одной командой.
112
+
113
+ Черновик читается владельцем как «работа не кончена»: кнопка слияния у него заблокирована самим хостингом, и по списку заявок готовое от недоделанного не отличить — серое и там и там. Довести отданное до снятого черновика обязан тот, кто его отдал.
114
+
115
+ Спроси прогон на вершине этим же ходом — `gh run list`, `gh pr checks` или сверку очереди работ — и сними черновик, когда он зелёный, а ветка сливается. Прогон ещё идёт — так и скажи владельцу, назвав его вывод.
116
+
117
+ Следующая задача берётся сверх этого, а не вместо: обе готовые заявки простояли черновиками ровно на такой подмене.
118
+
119
+ Гард судит один ход: следующий заход не отбивается."
120
+
121
+ # shellcheck disable=SC1090
122
+ [ -f "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/deny-tail.sh" ] \
123
+ && . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/deny-tail.sh" 2>/dev/null
124
+ command -v rt_deny_tail >/dev/null 2>&1 || rt_deny_tail() { :; }
125
+ deny_tail_text="$(rt_deny_tail "")"
126
+ [ -n "$deny_tail_text" ] && reason="${reason}
127
+
128
+ ${deny_tail_text}"
129
+
130
+ jq -n --arg r "$reason" '{decision:"block",reason:$r}' 2>/dev/null \
131
+ || printf '{"decision":"block","reason":"waiting-turn-guard: отданная работа осталась черновиком — спроси прогон и сними черновик."}\n'
132
+ exit 0
133
+ fi
134
+
99
135
  case "$verdict" in
100
136
  owe:pr) said="в этом ходе открыт PR" ;;
101
137
  owe:run) said="в этом ходе прочитан красный прогон" ;;
@@ -114,17 +114,17 @@ az repos pr update --id 205 --description "$(cat тело.md)"
114
114
 
115
115
  ## Оставшийся шаг
116
116
 
117
- После одобрения ветка получает ещё один коммит разбор папки задачи, и только потом
118
- вливается. До этого коммита вливать рано: папка уедет в главную ветку неразобранной.
117
+ Папка задачи разобрана коммитом `<sha>` за работой убрано. Осталось дождаться прогона и снять
118
+ черновик; до этого кнопка слияния заблокирована хостингом.
119
119
  ```
120
120
 
121
121
  Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
122
- — в тот ход, которым папка разбирается и снимается черновик:
122
+ — в тот ход, которым снимается черновик:
123
123
 
124
124
  ```markdown
125
125
  ## Оставшийся шаг
126
126
 
127
- Не осталось: папка задачи разобрана коммитом `<sha>`, черновик снят. Можно вливать.
127
+ Не осталось: прогон зелёный, черновик снят. Можно вливать.
128
128
  ```
129
129
 
130
130
  Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
@@ -141,17 +141,17 @@ Closes #86
141
141
 
142
142
  ## Оставшийся шаг
143
143
 
144
- После одобрения ветка получает ещё один коммит разбор папки задачи, и только потом
145
- вливается. До этого коммита вливать рано: папка уедет в главную ветку неразобранной.
144
+ Папка задачи разобрана коммитом `<sha>` за работой убрано. Осталось дождаться прогона и снять
145
+ черновик; до этого кнопка слияния заблокирована хостингом.
146
146
  ```
147
147
 
148
148
  Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
149
- — в тот ход, которым папка разбирается и снимается черновик:
149
+ — в тот ход, которым снимается черновик:
150
150
 
151
151
  ```markdown
152
152
  ## Оставшийся шаг
153
153
 
154
- Не осталось: папка задачи разобрана коммитом `<sha>`, черновик снят. Можно вливать.
154
+ Не осталось: прогон зелёный, черновик снят. Можно вливать.
155
155
  ```
156
156
 
157
157
  Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
@@ -125,17 +125,17 @@ Closes #86
125
125
 
126
126
  ## Оставшийся шаг
127
127
 
128
- После одобрения ветка получает ещё один коммит разбор папки задачи, и только потом
129
- вливается. До этого коммита вливать рано: папка уедет в главную ветку неразобранной.
128
+ Папка задачи разобрана коммитом `<sha>` за работой убрано. Осталось дождаться прогона и снять
129
+ черновик; до этого кнопка слияния заблокирована хостингом.
130
130
  ```
131
131
 
132
132
  Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное
133
- описание, — в тот ход, которым папка разбирается и снимается черновик:
133
+ описание, — в тот ход, которым снимается черновик:
134
134
 
135
135
  ```markdown
136
136
  ## Оставшийся шаг
137
137
 
138
- Не осталось: папка задачи разобрана коммитом `<sha>`, черновик снят. Можно вливать.
138
+ Не осталось: прогон зелёный, черновик снят. Можно вливать.
139
139
  ```
140
140
 
141
141
  Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
@@ -2,7 +2,7 @@
2
2
  name: task-flow-archive
3
3
  kind: pattern
4
4
  rule: task-flow
5
- description: Паттерн правила task-flow. Брать, когда работа доведена до готовности: разбор папки задачи последним коммитом, переезд в описание прошлого, сверка очереди работ, разбор закрытой работы правилами и то, что делать с его находками. Не брать для вливания договорённости и приведения текстов — это паттерн task-flow-close.
5
+ description: Паттерн правила task-flow. Брать, когда тексты приведены и папка задачи разбирается последним коммитом до открытия заявки: переезд в описание прошлого, сверка очереди работ, разбор закрытой работы правилами и то, что делать с его находками. Не брать для вливания договорённости, открытия заявки и снятия черновика — это паттерн task-flow-close.
6
6
  ---
7
7
 
8
8
  # Разбор папки задачи и разбор работы правилами
@@ -14,7 +14,7 @@ description: Паттерн правила task-flow. Брать, когда р
14
14
  ## Когда брать
15
15
 
16
16
  - Договорённость влита, тексты домена приведены, и папка задачи разбирается последним
17
- коммитом ветки.
17
+ коммитом ветки — до открытия заявки, а не после одобрения.
18
18
  - Работа слита человеком, и её разбирают правилами.
19
19
  - Разбор вернул находки, и их надо куда-то положить.
20
20
 
@@ -55,8 +55,12 @@ cat docs/tasks/<КЛЮЧ>-<номер>-<slug>/grill.md > docs/archive/<ЧТО_Р
55
55
  rm -r docs/tasks/<КЛЮЧ>-<номер>-<slug>
56
56
  ```
57
57
 
58
- Разбор идёт в том же PR, что и работа: папка, оставленная до мержа, попадает в главную
59
- ветку и читается там как текущая.
58
+ Разбор идёт последним коммитом ветки, до открытия заявки: открытие с лежащей папкой отбивает
59
+ гард поставки. Прежде уборка стояла после одобрения — считалось, что замысел нужен на диске всё
60
+ время разбора. Но кнопку слияния нажимает человек на хостинге, куда гард не достаёт, и вливает
61
+ он, как только видит зелёное: трижды подряд папка уехала в главную неразобранной. Замысла после
62
+ уборки на диске нет намеренно, и правку по замечаниям гард хода работы пропускает по признаку
63
+ из истории ветки.
60
64
 
61
65
  ### Работа, разбирающая чужую папку, разбирает две
62
66
 
@@ -75,8 +79,8 @@ rm -r docs/tasks/<своя>
75
79
  Две записи в архиве, а не одна: работы разные, и решения в них разные. Сверка очереди работ
76
80
  после этого не называет ни одной папки — этим и проверяется, что разобраны обе.
77
81
 
78
- **Следующее движение:** разобранная папка уезжает в ветку тем же коммитом, и следом за ним
79
- сверяется очередь работ.
82
+ **Следующее движение:** разобранная папка уезжает в ветку тем же коммитом, следом сверяется
83
+ очередь работ, и тем же ходом открывается заявка — паттерн `task-flow-close`.
80
84
 
81
85
  ## Состояние `папка-разобрана`: сверка очереди работ
82
86
 
@@ -87,7 +91,7 @@ npm run check:docs # пути, названные в текстах, суще
87
91
  ```
88
92
 
89
93
  **Следующее движение:** расхождения, названные сверками, чинятся тем же ходом; чинить нечего —
90
- тот же ход снимает черновик и просит владельца влить, называя номер.
94
+ тот же ход открывает заявку черновиком и называет владельцу номер, паттерн `task-flow-close`.
91
95
 
92
96
  ## Состояние `влито`: работа разбирается правилами — фоном, следом за PR
93
97
 
@@ -156,20 +160,18 @@ npm run check:docs # пути, названные в текстах, суще
156
160
 
157
161
  ## Ловушки
158
162
 
159
- - **Папку разбирают до слияния — потом о ней уже никто не вспомнит.** Сверка очереди считает
160
- задачу закрытой по слиянию: до него папка среди текущих законна, а после за неё никто не
161
- отвечает — работа перешла к следующей задаче, и находка достанется чужому заходу. Три раза
162
- подряд папка закрытой задачи так и уехала в главную ветку, в последний раз их набралось
163
- пять. Теперь это держит гард поставки: слияние отбивается, пока папка лежит в ветке.
164
- - **Разбирают последним коммитом, а не перед открытием PR.** Пока идёт ревью, замысел
165
- нужен на диске: без него правку по замечаниям не пропустит гард хода работы. Порядок такой:
166
- правки по ревью, потом разбор папки, потом слияние.
167
- - **Разбор папки идёт последним, после того как гейт пуша прошёл целиком.** Гард хода работы
168
- не пускает правку кода приложения без замысла на диске, а после разбора замысла нет: чужое
169
- замечание линтера, приехавшее мержем из главной ветки, чинить уже нечем, и гейт пуша стоит.
170
- Порядок один: мерж главной ветки, все линтеры и проверки зелёные, вливание договорённости,
171
- приведение текстов домена, разбор папки. Понадобилась правка кода после разбора — замысел
172
- восстанавливается на диске на время правки, и разбор повторяется тем же коммитом.
163
+ - **Папку разбирают до открытия заявки — потом о ней уже никто не вспомнит.** Сверка очереди
164
+ считает задачу закрытой по слиянию: после него за папку никто не отвечает работа перешла к
165
+ следующей задаче, и находка достанется чужому заходу. Три раза подряд папка закрытой задачи
166
+ так и уехала в главную ветку, в последний раз их набралось пять. Держит это гард поставки:
167
+ открытие заявки отбивается, пока папка лежит в ветке.
168
+ - **Разбор папки идёт последним коммитом, после того как гейт пуша прошёл целиком.** Порядок
169
+ один: мерж главной ветки, все линтеры и проверки зелёные, вливание договорённости, приведение
170
+ текстов домена, разбор папки и только потом заявка.
171
+ - **После разбора замысла на диске нет, и собирать папку заново не надо.** Правку по замечаниям
172
+ разбора и починку красного прогона гард хода работы пропускает по признаку из истории ветки:
173
+ папка, снятая её коммитом, и есть признак отданной работы. Собранная заново папка вернула бы
174
+ отказ гарда поставки на следующем же вызове.
173
175
  - **Если папку просто удалить, первым пропадёт `grill.md`.** Удалить проще, чем разобрать, а
174
176
  слова владельца записаны только там, и восстановить их неоткуда. Поэтому гард требует, чтобы
175
177
  ветка добавила запись в архив. Что именно перенесли, он не проверяет — это смотрит владелец