@rt-tools/agent-kit 0.17.0 → 0.19.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 (75) hide show
  1. package/assets/checks/board-epics.github.mjs +123 -0
  2. package/assets/checks/board-gh.github.mjs +121 -0
  3. package/assets/checks/board.github.mjs +77 -73
  4. package/assets/checks/check-board.github.mjs +39 -3
  5. package/assets/checks/check-hook-scope.mjs +126 -0
  6. package/assets/checks/check-profile-drift.mjs +195 -0
  7. package/assets/checks/check-specs.mjs +1 -1
  8. package/assets/checks/rt-kit-checks.config.mjs +13 -0
  9. package/assets/checks/spec-anchors.mjs +2 -2
  10. package/assets/defaults/project.sh +21 -117
  11. package/assets/defaults/shell.sh +139 -0
  12. package/assets/hooks/browser-guard-no-other-drivers.sh +41 -2
  13. package/assets/hooks/claim-guard.sh +22 -1
  14. package/assets/hooks/docs-guard.sh +1 -1
  15. package/assets/hooks/exam-guard.sh +85 -12
  16. package/assets/hooks/git-guard-delivery-conflict.sh +85 -0
  17. package/assets/hooks/git-guard-delivery-signature.sh +14 -5
  18. package/assets/hooks/git-guard-delivery.sh +15 -2
  19. package/assets/hooks/grill-gate.sh +63 -6
  20. package/assets/hooks/proposal-guard.sh +11 -4
  21. package/assets/hooks/rule-source-guard.sh +8 -13
  22. package/assets/hooks/task-context-load.sh +22 -0
  23. package/assets/hooks/task-flow-context.sh +9 -0
  24. package/assets/hooks/task-flow-draft-guard.sh +17 -0
  25. package/assets/hooks/turn-exit-guard.sh +45 -87
  26. package/assets/hooks/waiting-turn-guard.sh +65 -2
  27. package/assets/hooks/work-start-guard.sh +166 -0
  28. package/assets/hooks/write-targets.sh +24 -0
  29. package/assets/laws/verifiability.md +28 -0
  30. package/assets/patterns/browser-verification-measure.md +49 -1
  31. package/assets/patterns/browser-verification-stand.md +10 -2
  32. package/assets/patterns/doc-style-write.md +21 -1
  33. package/assets/patterns/git-workflow-commit.github.md +32 -3
  34. package/assets/patterns/git-workflow-docker.md +8 -0
  35. package/assets/patterns/git-workflow-freshness.md +87 -0
  36. package/assets/patterns/git-workflow-merge.md +23 -0
  37. package/assets/patterns/git-workflow-pr.github.md +6 -0
  38. package/assets/patterns/git-workflow-restart.md +18 -0
  39. package/assets/patterns/git-workflow-stack.md +30 -0
  40. package/assets/patterns/lib-layers-move.md +4 -0
  41. package/assets/patterns/spec-driven-domain.md +13 -1
  42. package/assets/patterns/spec-driven-rule.md +5 -4
  43. package/assets/patterns/spec-driven-sweep.md +1 -1
  44. package/assets/patterns/status-report-table.github.md +1 -1
  45. package/assets/patterns/task-flow-archive.md +12 -2
  46. package/assets/patterns/task-flow-close.md +31 -24
  47. package/assets/patterns/task-flow-handoff.md +14 -2
  48. package/assets/patterns/task-flow-resume.md +18 -3
  49. package/assets/patterns/task-flow-start.md +23 -23
  50. package/assets/patterns/testing-e2e.md +23 -0
  51. package/assets/patterns/turn-entry-map.md +1 -1
  52. package/assets/pitfalls/agent-kit.md +4 -6
  53. package/assets/pitfalls/doc-style.md +10 -0
  54. package/assets/pitfalls/git-workflow.github.md +20 -0
  55. package/assets/pitfalls/spec-driven.md +6 -0
  56. package/assets/pitfalls/task-flow.md +20 -0
  57. package/assets/pitfalls/testing.md +6 -0
  58. package/assets/pitfalls/turn-conduct.md +35 -0
  59. package/assets/rules/browser-verification.md +19 -0
  60. package/assets/rules/deploy-flow.github.md +9 -0
  61. package/assets/rules/doc-style.md +6 -0
  62. package/assets/rules/git-workflow.azure.md +17 -2
  63. package/assets/rules/git-workflow.github.md +89 -90
  64. package/assets/rules/git-workflow.gitlab.md +12 -4
  65. package/assets/rules/lists.md +5 -0
  66. package/assets/rules/observability.needs-app.md +4 -0
  67. package/assets/rules/reuse-first.md +6 -0
  68. package/assets/rules/spec-driven.md +29 -25
  69. package/assets/rules/task-flow.md +52 -46
  70. package/assets/rules/testing.md +27 -1
  71. package/assets/rules/turn-conduct.md +46 -43
  72. package/assets/skills/agent-kit.md +9 -0
  73. package/package.json +1 -1
  74. package/rt-tools-agent-kit-0.19.0.tgz +0 -0
  75. package/rt-tools-agent-kit-0.17.0.tgz +0 -0
@@ -11,6 +11,10 @@ description: Паттерн правила git-workflow. Брать, когда
11
11
  `docs/constitution/delivery.md`. Разбор одного конфликта — паттерн `git-workflow-merge`,
12
12
  открытие одной заявки — `git-workflow-pr`.
13
13
 
14
+ **Вызовы здесь даны клиентом GitHub.** Дерево на другом хостинге читает их как форму, а команду
15
+ берёт у своего клиента: имена полей и подкоманд у клиентов разные, а спрашиваемое — одно.
16
+ Соответствие называет редакция правила поставки, разложенная в этом дереве.
17
+
14
18
  ## Когда брать
15
19
 
16
20
  - Из одного основания заведено больше двух веток, и все ждут слияния.
@@ -48,6 +52,13 @@ gh pr create --base <предыдущая ветка> --title '[<КЛЮЧ>-<но
48
52
  Порядок вливания стоит в теле каждой заявки строкой «стоит на #<номер>, вливать после него»:
49
53
  владелец вливает по списку, а родство веток по списку не видно.
50
54
 
55
+ **Конвейер дерева проверяется на то, слушает ли он заявку с таким основанием.** Событие заявки
56
+ хостинг шлёт с фильтром по базе, и дерево, оставившее в фильтре одну главную ветку, всей череде
57
+ прогонов не даёт вовсе: заявка стоит зелёно-пустой, а вернуть событие нечем — ни новый коммит,
58
+ ни перезакрытие заявки базы не меняют. Спрашивается это до того, как череду заводить: у
59
+ настройки конвейера, а не у страницы заявки, где отсутствие прогона выглядит так же, как его
60
+ ожидание.
61
+
51
62
  ```bash
52
63
  # порядок череды целиком — снизу вверх
53
64
  gh pr list --state open --json number,headRefName,baseRefName \
@@ -141,6 +152,25 @@ done | sort | uniq -c | sort -rn | head
141
152
  конфликт там, где подряд его бы не было. Порядок называется владельцу в теле заявки — кнопки
142
153
  нажимает он, а о родстве веток не знает.
143
154
 
155
+ ## Волна веток проверяется пробным слиянием
156
+
157
+ Ветка, лежащая невлитой рядом с соседками, зелена сама по себе: линт, тесты, сборки и сверки
158
+ она проходит одна. Сталкивается она с ними тем, чего на отдельной ветке не видит ни одна
159
+ проверка — тот же следующий свободный номер сценария, тот же заведённый новым файл, та же
160
+ правленная строка отметки. После слияния первые два чинятся уже в главной и стоят отдельной
161
+ работы.
162
+
163
+ ```bash
164
+ git fetch origin
165
+ git checkout -b probe-merge origin/main
166
+ for b in <ветка-1> <ветка-2> <ветка-3>; do git merge --no-edit "origin/$b" || break; done
167
+ npm run check:all
168
+ git checkout - && git branch -D probe-merge
169
+ ```
170
+
171
+ Ветка пробы удаляется, а находки и порядок слияния записываются туда, где живёт замысел линии
172
+ работ: пробное слияние отвечает на «что столкнётся», а не заменяет собой отдачу.
173
+
144
174
  ## Частые промахи
145
175
 
146
176
  - Открыты все заявки разом, потому что ветки были готовы. Готовность ветки признаком того, что
@@ -77,6 +77,10 @@ grep -rn "@<область>/<семья>/<домен>" libs/ apps/ | sed 's/:.*/
77
77
  npx nx run-many -t lint --projects=<список по изменённым файлам>
78
78
  ```
79
79
 
80
+ Этот прогон — быстрый, по горячим следам переноса, и набором перед пушем он не бывает:
81
+ набор, собранный по изменённым файлам, пропускает то, до чего правка дошла связями. Перед
82
+ пушем идёт тот же набор, что гоняет конвейер, и теми же командами.
83
+
80
84
  ## Проверить
81
85
 
82
86
  ```bash
@@ -54,6 +54,18 @@ docs/specs/<домен>/
54
54
  такой спек по строкам бесполезно, потому что делится в нём не описание домена, а ненаписанное
55
55
  правило.
56
56
 
57
+ **Заголовок записи раздела решений датой не называется.** Дата говорит, когда решение приняли, а
58
+ раздел отвечает на «почему так, а не иначе»: по дате решение не отобрать и не найти, зато
59
+ названная ею запись читается описанием прошлого и остаётся в спеке навсегда. Запись начинается с
60
+ самого решения.
61
+
62
+ **Утверждение, стоящее в другом разделе того же спека, вторым пунктом правил не заводится.**
63
+ Устройство записи живёт в разделе данных, порядок вызовов — в разделе контракта, причина
64
+ существования домена — в разделе «Зачем»: все три говорят о том же, о чём говорило бы правило.
65
+ Второй экземпляр расходится с первым молча, и заметить это нечем — сверка знает пункт правила
66
+ против якоря, а два утверждения об одном не сравнивает никто. Решение при этом из раздела решений
67
+ уезжает целиком: место, где требование живёт, найдено.
68
+
57
69
  Шапка несёт статус, дату ревизии, префикс сценариев, зависимости от других доменов, строку
58
70
  `**Законы:**` — законы, которые домен применяет, — и строку `**Процедуры:**` — корни либ, чьи
59
71
  процедуры домен обслуживает.
@@ -84,7 +96,7 @@ docs/specs/<домен>/
84
96
  ```
85
97
 
86
98
  Правило, которому места в коде не нашлось, — намерение: ему место в «Открытых вопросах» как
87
- `Q-N`, а не формальный якорь.
99
+ `Q-<буква закона>-<номер>`, а не формальный якорь.
88
100
 
89
101
  ## Сценарий
90
102
 
@@ -33,7 +33,10 @@ description: Паттерн правила spec-driven. Брать при зав
33
33
  вопрос есть, и стираются вместе с последним закрытым: закрытый вопрос из закона убирается, а
34
34
  не превращается в пустой раздел.
35
35
 
36
- Ни истории правок, ни доводов о том, почему когда-то выбрали так, в законе нет. Историю
36
+ Даты в законе тоже нет: у одного закона из семнадцати она стояла, у остальных не появлялась
37
+ никогда, а прочитанная как срок годности — старит верный текст, которого никто не трогал, потому
38
+ что трогать было нечего. Ни истории правок, ни доводов о том, почему когда-то выбрали так, в
39
+ законе нет. Историю
37
40
  держит система контроля версий, а довод с отвергнутой альтернативой — свойство работы, а не
38
41
  продукта: ему место в «Ловушках» правила под этим законом, где и путям к файлам можно.
39
42
  Утверждение, которое нельзя написать как «верно всегда», статьёй не становится вовсе.
@@ -43,8 +46,6 @@ description: Паттерн правила spec-driven. Брать при зав
43
46
 
44
47
  Как правка доезжает до работающего приложения. …
45
48
 
46
- **Ревизия:** 2026-08-05
47
-
48
49
  ## Статьи
49
50
 
50
51
  - **Выкатывается образ того коммита, который выкатывают.** Умолчание «последний» отстаёт от
@@ -98,7 +99,7 @@ description: Правило под «Закон о поставке». Брат
98
99
  ```
99
100
 
100
101
  Утверждение, которому места в коде не нашлось, в этот раздел не ставится: оно уходит прозой в
101
- «Ловушки» или вопросом `Q-N` в закон.
102
+ «Ловушки» или вопросом `Q-<буква закона>-<номер>` в закон.
102
103
 
103
104
  ## Паттерн
104
105
 
@@ -47,7 +47,7 @@ description: Паттерн правила spec-driven. Брать при спл
47
47
  тридцати шести строк расхождений не оказалось ни одной. Поэтому число находок прошлого домена на
48
48
  следующий не переносится — переносится только сам порядок проходов.
49
49
 
50
- ## Ловушки
50
+ ## Частые промахи
51
51
 
52
52
  - **Урожайность прохода обещана фактом.** «Проход даст столько-то» — оценка, и по чужому слою она
53
53
  промахивается целиком. Разбор просьбы называет проходы, а не число находок.
@@ -57,7 +57,7 @@ gh api repos/:owner/:repo/issues/<номер> --jq '{t:.title,s:.state,labels:[.
57
57
  имя команды в оболочке бывает занято чужим псевдонимом, и тогда вызов уходит в интерактивный
58
58
  вход вместо ответа.
59
59
 
60
- ## Ловушки
60
+ ## Частые промахи
61
61
 
62
62
  - **Задача на борде читается запросом, а не подкомандой просмотра.** Подкоманда тянет за собой
63
63
  доски старого образца, хостинг отвечает отказом о них, и вызов краснеет целиком, ничего не
@@ -46,7 +46,17 @@ description: Паттерн правила task-flow. Брать, когда т
46
46
  | `grill.md` | в `docs/archive/` — ответы владельца невосстановимы, и это единственная запись о том, почему задача поставлена так |
47
47
  | `progress.md` | в `docs/archive/`, если в нём есть решения по ходу с причинами; иначе удаляется |
48
48
  | `plan.md` | удаляется — после выкатки на его вопрос отвечает код, а на «как работает» отвечает спек домена |
49
- | находки разбора | переезжают к замыслу эпика — их читает владелец, когда эпик кончится; работа вне эпика показывает их сразу |
49
+ | находки разбора | пишутся сразу рядом с замыслом эпика — не переезжают отсюда; работа вне эпика показывает их владельцу тем же ходом |
50
+
51
+ Находки в папке задачи не живут вовсе. Разбор идёт фоном, и когда он кончится, не знает никто:
52
+ папка к этой минуте разобрана, а ветка бывает уже влита и снята. Оба срока назначает не
53
+ исполнитель, поэтому переезд «из папки к замыслу эпика» держался бы на совпадении, которого может
54
+ и не случиться. Тем же местом пользуется находка, замеченная не разбором, а по ходу работы.
55
+
56
+ Находки, вернувшиеся после того, как ветка ушла, едут веткой следующей задачи: пуш в снятую ветку
57
+ её не обновляет, а заводит заново, и коммит остаётся вне главной. Следующая задача к этой минуте
58
+ уже взята — её веткой уборка за предыдущей и едет, тем же порядком, каким разбирают чужую папку
59
+ задачи. Эпик кончился и следующей задачи нет — находки уезжают своей задачей.
50
60
 
51
61
  Уезжающее складывается одним файлом с говорящим именем, а не папкой из трёх:
52
62
 
@@ -187,7 +197,7 @@ npm run cargo:mark -- --state fixed \
187
197
  котором владелец сказал вслух, уходит наружу в тот же ход: написанное и не отправленное лежит в
188
198
  дереве неотличимо от отправленного.
189
199
 
190
- ## Ловушки
200
+ ## Частые промахи
191
201
 
192
202
  - **Папку разбирают до открытия заявки — потом о ней уже никто не вспомнит.** Сверка очереди
193
203
  считает задачу закрытой по слиянию: после него за папку никто не отвечает — работа перешла к
@@ -258,33 +258,40 @@ PR #<номер> готов к слиянию: прогон зелёный, че
258
258
  ветки. Что именно чинится, берётся из замечания, а не из замысла.
259
259
 
260
260
  Главная ветка, влитая ради того, чтобы что-то посмотреть, — такая же правка, как влитая ради
261
- работы, и уезжает тем же ходом. Конфликт тут ни при чём: он делает промах заметнее, а не создаёт
262
- его. Слияние, оставшееся в рабочей копии, либо пушится тем же ходом, либо не делается — иначе
263
- владелец видит прежнее состояние и решает по нему.
261
+ работы, и уезжает тем же ходом. Слияние, оставшееся в рабочей копии, либо пушится тем же ходом,
262
+ либо не делается иначе владелец видит прежнее состояние и решает по нему.
264
263
 
265
264
  **Следующее движение:** прогон зелёный и замечаний нет — черновик снимается, и владельцу
266
265
  говорится, что работа готова.
267
266
 
268
- ## Ловушки
269
-
270
- - **Тексты правятся до разбора папки.** Список того, что перечитывать, лежит в замысле, а
271
- разбор папки его удаляет. После разбора остаётся только память о том, что задевали.
272
- - **Утверждение правила снимается вместе со строкой привязки.** Связь идёт по тексту
273
- утверждения. Убрали утверждение и оставили строку в `implementation.md` сверка спеков
274
- краснеет; убрали строку и оставили утверждение тоже.
267
+ ## Частые промахи
268
+
269
+ - **Тексты правятся до разбора папки:** список того, что перечитывать, лежит в замысле, а разбор
270
+ папки его удаляет.
271
+ - **Запись раздела решений, повторяющая статью правила слово в слово, доводом при ней не
272
+ считается.** Правило приходит в контекст само, спектолько когда его открыли; пара расходится
273
+ молча. Такая запись уезжает целиком, даже если раздел пустеет; довод, в статье не сказанный,
274
+ дописывается в статью.
275
+ - **Тело заявки остаётся старше разбора папки.** Разбор — последний коммит ветки, и он делает
276
+ неправдой всё, что тело обещало сделать до слияния. Ревьювер читает список оставшегося как
277
+ оставшееся, поэтому тело правится тем же ходом.
278
+ - **Утверждение правила снимается вместе со строкой привязки.** Связь идёт по тексту: строка без
279
+ утверждения и утверждение без строки одинаково краснят сверку спеков.
275
280
  - **Раздел «Чего из закона здесь нет» читается глазами, греп тут не помогает.** Искать
276
- приходится не то слово, которое ждёшь: правило ссылалось на статью закона, которой в законе
277
- нет вовсе, и по слову из своей темы эта строка находилась — а неправда была в другом.
278
- - **Сказать «сверено», не открыв файл, нельзя.** Правило читается целиком. Устаревшее
279
- утверждение стоит в списке среди верных и ничем от них не отличается.
281
+ приходится не то слово, которое ждёшь: правило ссылалось на статью, которой в законе нет, и по
282
+ слову своей темы эта строка находилась — а неправда была в другом.
283
+ - **Сказать «сверено», не открыв файл, нельзя.** Правило читается целиком: устаревшее утверждение
284
+ стоит среди верных и ничем от них не отличается.
280
285
  - **Вливание после мержа не делается.** В главной ветке тогда лежит раздел «предложено, но не
281
- выкачено» с тем, что работает месяц, беззвучная ложь, тем убедительнее, чем старше.
282
- - **Номера сценариев при вливании не пересчитываются.** Идентификатор — ключ связи с тестами;
283
- сдвиг рвёт сверку у соседей, которых правка не касалась.
284
- - **«Что не входит» после вливания читается целиком, а не дописывается.** Договорённость несёт
285
- свои границы, и при вливании они ложатся рядом с границами домена: половина повторяет уже
286
- стоявшее другими словами, а строка «этого раздела ещё нет» становится ложью ровно той
287
- работой, которая её вливает. Сверка спеков в этот раздел не смотрит вовсе. Снимается
288
- дословный повтор и то, что работа сделала входящим.
289
- - **Правило без привязки в спек домена не въезжает.** Кода, который его исполняет, нет
290
- значит это намерение, и место ему в открытых вопросах домена, а не в правилах.
286
+ выкачено» с тем, что работает месяц: беззвучная ложь, тем убедительнее, чем старше.
287
+ - **Номера сценариев при вливании не пересчитываются.** Идентификатор — ключ связи с тестами, и
288
+ сдвиг рвёт сверку у соседей.
289
+ - **«Что не входит» после вливания читается целиком, а не дописывается.** Границы фичи ложатся
290
+ рядом с границами домена: половина повторяет стоявшее другими словами, а строка «этого раздела
291
+ ещё нет» становится ложью той работой, которая её вливает. Сверка спеков туда не смотрит.
292
+ - **Своя строка сверки очереди ищется по имени** по номеру задачи и имени ветки: сверка
293
+ отвечает про всё дерево, и на одном закрытии чужих папок было восемь при одной своей.
294
+ - **Пара «метка объёма и строка в замысле эпика» рвётся с двух сторон:** задача по следу закрытой
295
+ наследует метку без строки о заходах, а закрытый эпик уносит строку у всех, кто её несёт.
296
+ - **Правило без привязки в спек домена не въезжает.** Кода, который его исполняет, нет — значит
297
+ это намерение, и место ему в открытых вопросах домена.
@@ -89,6 +89,8 @@ mkdir -p <каталог передачи>
89
89
  ```markdown
90
90
  Работа: <КЛЮЧ>-<номер> «<название задачи>». Рабочее дерево — <полный путь>, ветка
91
91
  <КЛЮЧ>-<номер>-<slug> (заведена, в работе).
92
+ Заявка: #<номер>, открыта, ждёт разбора владельцем. Свежесть её основания здесь не записана
93
+ намеренно — она протухает; спрашивается она у хранилища первым делом нового захода.
92
94
 
93
95
  Ход работы и замысел придут на запуске сессии хуком — перечитывать их файлами не надо. Разбор
94
96
  просьбы владельца лежит в папке задачи и читается, когда непонятна причина решения.
@@ -128,7 +130,8 @@ mkdir -p <каталог передачи>
128
130
 
129
131
  Разделы фиксированы, и порядок у них тот же:
130
132
 
131
- 1. **Работа** — номер задачи, её название, рабочее дерево полным путём, ветка и её состояние.
133
+ 1. **Работа** — номер задачи, её название, рабочее дерево полным путём, ветка и её состояние; у
134
+ отданной работы — номер открытой заявки и то, чего она ждёт.
132
135
  2. **Где искать** — что придёт хуком само, а что читается по надобности.
133
136
  3. **Эпик** — таблица положения; у работы вне эпика раздела нет.
134
137
  4. **Сделано и следующий шаг** — одной строкой каждое; подробности уже в ходе работы.
@@ -142,14 +145,23 @@ mkdir -p <каталог передачи>
142
145
  заход одной вставкой. Пересказывать содержание передачи в ответе не надо: владелец её и так
143
146
  прочитает, а место на неё уже потрачено.
144
147
 
145
- ## Ловушки
148
+ ## Частые промахи
146
149
 
147
150
  - **Заход закрывается на втором пороге, а не начинает на нём новый этап.** Напоминание на
148
151
  первом — это уже сигнал выбирать точку, а не работать дальше, пока не отобьют.
149
152
  - **Передача пишется как пересказ переписки.** В неё идёт то, чего нет ни в ходе работы, ни в
150
153
  правилах: дерево, ветка, состояние стендов. Всё остальное следующий заход прочитает сам.
154
+ - **Утверждение о состоянии работы берётся в тот же ход, а не вспоминается.** Родитель задачи,
155
+ её колонка, открытая заявка, влитая ветка, поднятые стенды живут вне захода и меняются без
156
+ него, а передача читается первой и не оспаривается: заход исполняет её указание, а не проверяет
157
+ его. Правдоподобие подтверждением не считается — «ветка не влита, значит и родителя нет» это
158
+ вывод, а не замер. Спросить нечем — так и пишется вопросом: «родитель не проверен, проверить
159
+ перед заявкой».
151
160
  - **Состояние работы в передачу не переезжает.** Сделанное отмечается в ходе работы — одной
152
161
  записью; передача его пересказывает, но не заменяет и в дерево не коммитится.
162
+ - **В передачу записано состояние, которое живёт часами.** Отставание от главной ветки, ход
163
+ прогона и «проверки зелёные» новый заход читает как верное сегодня. В передачу идёт то, что не
164
+ меняется без участия исполнителя: дерево, ветка, номер заявки, что не закоммичено.
153
165
  - **Незакоммиченное не названо.** Работа живёт в дереве неделями, и строка «что лежит
154
166
  несохранённым и почему» — единственное, по чему это видно.
155
167
  - **Заход, кончившийся ничем, тоже пишет передачу.** «Пробовали так — не вышло, потому что» —
@@ -27,6 +27,11 @@ description: Паттерн правила task-flow. Брать при возв
27
27
  образца, а `progress.md` заполняется по тому, что видно в дереве и в истории ветки, а не по
28
28
  расспросам владельца.
29
29
 
30
+ Пришло «РАБОТА ЗАКРЫВАЕТСЯ» — папку разобрала сама ветка перед заявкой, и собирать её заново не
31
+ надо: состояние работы читается у заявки и в передаче захода. Понадобилась правка кода по
32
+ замечаниям разбора — папка восстанавливается на время правки, а разбор повторяется тем же
33
+ коммитом.
34
+
30
35
  ## Чего не делать
31
36
 
32
37
  - **Не спрашивать владельца о том, что записано.** Ради этого всё и заведено.
@@ -139,19 +144,25 @@ git log --oneline origin/main..HEAD
139
144
  Берётся, а не выбирается: порядок назначен на планировании и лежит в замысле эпика. Выбор,
140
145
  предложенный владельцу при назначенном порядке, — просьба назначить его заново.
141
146
 
147
+ У работы вне эпика замысла с порядком нет, и следующая берётся из очереди работ — тем же
148
+ движением и с тем же запретом на выбор вслух: очередь спрашивается командой, а не памятью о том,
149
+ что заводил сам исполнитель. Пусто в очереди — это утверждение о дереве, и подтверждается оно
150
+ выводом команды.
151
+
142
152
  ```bash
143
153
  # что назначено следующим — читается в замысле эпика, а не спрашивается
144
154
  # состояние задач — в очереди работ: замысел о закрытом не знает
145
155
  ```
146
156
 
147
157
  Останавливает заход только предел заполнения окна — тогда идёт передача, паттерн
148
- `task-flow-handoff`. Эпик кончился заход закрывается тем же порядком, и владельцу называется,
149
- что кончился именно эпик, а не одна его задача.
158
+ `task-flow-handoff`. Кончившийся эпик поводом остановиться не бывает: работа берётся вне его
159
+ из очереди работ, — а владельцу тем же ходом называется, что кончился именно эпик, а не одна его
160
+ задача. Он называется вместе со взятой работой, а не вместо неё.
150
161
 
151
162
  **Следующее движение:** по следующей задаче делается действие — заведена задача, ветка или
152
163
  папка. Ход кончается после него, а не после слов о нём.
153
164
 
154
- ## Ловушки
165
+ ## Частые промахи
155
166
 
156
167
  - **Заход, кончившийся ничем, тоже записывается.** Иначе следующий пойдёт той же дорогой:
157
168
  «пробовали так — не вышло, потому что» стоит одной строки и экономит целый заход.
@@ -173,3 +184,7 @@ git log --oneline origin/main..HEAD
173
184
  через один ход после записи механизм повторился в той же форме. Поэтому разбор кончается не
174
185
  текстом, а тем, что из него вышло: правкой ресурса, гардом или предложением с адресом. Заход,
175
186
  дописавший разбор и вернувшийся к работе прежним, платит за него дважды.
187
+ - **Число находок, написанное словом, устаревает к следующему абзацу.** Счёт растёт заходами, а
188
+ слово стоит на месте: «семь» простояло над восемью перечисленными до самого итога и поехало бы
189
+ дальше — в отчёт и в замысел эпика. Пишется либо перечень без числа, либо число, посчитанное
190
+ тем же ходом, каким пишется итог.
@@ -12,7 +12,8 @@ description: Паттерн правила task-flow. Брать в начале
12
12
 
13
13
  ## Когда брать
14
14
 
15
- - Владелец просит что-то сделать, и работы больше, чем на одну реплику.
15
+ - Владелец просит что-то сделать; размер просьбы значения не имеет папка заводится под любую
16
+ работу.
16
17
  - Замеченный по ходу дефект становится задачей.
17
18
 
18
19
  ## Порядок
@@ -41,23 +42,22 @@ Agent(subagent_type: "Explore", prompt: "<тема просьбы>: что по
41
42
 
42
43
  Разведка, не нашедшая ничего, разрешением спрашивать не становится. Сначала называется, где
43
44
  искали, потом добираются места, которых в списке не было: замысел эпика, описание прошлого,
44
- записи прошлых заходов.
45
+ записи прошлых заходов. Одно место отрицанием не является: «в таком-то месте не нашёл» говорит о
46
+ месте, а не о дереве, и вопрос называет оба способа, которыми искали.
45
47
 
46
48
  Разведка кончается не ощущением, а выводом команд. До первого вопроса владельцу исполнитель
47
49
  знает: как устроен репозиторий (корневая памятка), что лежит в каталоге, о котором пойдёт речь
48
- (`ls`), и есть ли уже написанное по теме (поиск по документации и правилам). Вопрос называет,
49
- где искали: «в таком-то месте не нашёл» проверяемо, «не знаю» нет. Без списка того, что
50
- считается сделанным, разведка исполняется как настроение: прочитанный переданный текст сходит
51
- за неё, и по текущему дереву не запускается ни одной команды.
50
+ (`ls`), и есть ли уже написанное по теме (поиск по документации и правилам). «Не знаю»
51
+ проверяемым не бывает. Без списка того, что считается сделанным, разведка исполняется как
52
+ настроение: прочитанный переданный текст сходит за неё, и по текущему дереву не запускается ни
53
+ одной команды.
52
54
 
53
55
  Разведка по заведённой задаче кончается воспроизведённым симптомом, а не найденным файлом. Тело
54
- задачи описывает дерево на день заведения, и между заведением и работой в главную ветку въезжают
55
- чужие правки: разведка, читающая код по именам из тела, подтверждает, что названные файлы на
56
- месте, — и отпавшая задача от живой не отличается ничем. Прежде первой своей правки разведка
57
- повторяет то, на что задача жалуется: зовёт процедуру, читает отданный ответ, гоняет проверку,
58
- которая молчала. Симптом не воспроизвёлся — задача закрывается как отпавшая, и это законный её
59
- исход: чинить нечего, а зелёные проверки после такой правки говорят ровно об этом и ни о чём
60
- больше.
56
+ задачи описывает дерево на день заведения, и чужие правки въезжают в главную ветку между
57
+ заведением и работой: разведка по именам из тела подтверждает, что файлы на месте, — и отпавшая
58
+ задача от живой не отличается ничем. Прежде первой своей правки разведка повторяет то, на что
59
+ задача жалуется: зовёт процедуру, читает ответ, гоняет молчавшую проверку. Симптом не
60
+ воспроизвёлся — задача закрывается отпавшей, и это законный её исход.
61
61
 
62
62
  **Следующее движение:** находки ложатся в разбор, и тем же ходом владельцу уходит первый из
63
63
  шести вопросов. Разведка кончилась — состояние осталось прежним, ход тоже.
@@ -84,14 +84,15 @@ Agent(subagent_type: "Explore", prompt: "<тема просьбы>: что по
84
84
  заходе, включая исходную просьбу. Слово, повторённое в просьбе несколько раз, ответом является.
85
85
  Закрытый вопрос отмечается в разборе просьбы вместе с тем, чем он закрыт.
86
86
 
87
- Объём работы основанием для вопроса о границах не бывает. «Это большая работа» и «делать ли её
88
- целиком» разные вопросы: первый исполнитель решает сам, второй владелец решает раньше, чем
89
- работа началась. Вопрос о границах задаётся тогда, когда владелец границ не назвал, — а не
90
- тогда, когда названные оказались широкими.
87
+ Закрыть его можно и допущением, когда ответ очевиден: в разборе стоит строка «вопрос закрыт
88
+ допущением: <что принято>». Неверное допущение стоит правки, вопрос ради очевидного захода.
91
89
 
92
- Форму вопроса задают настройки владельца: где они требуют меню, спрашивается меню, и тогда к
93
- каждому вопросу добавляется свободный варианту закрытого набора нет строки «вопрос не тот».
94
- Выбор слова, имени и термина уточняется прозой в любом случае.
90
+ Объём работы основанием для вопроса о границах не бывает: «это большая работа» решает
91
+ исполнитель, «делать ли её целиком»владелец, и решает раньше, чем работа началась. Вопрос о
92
+ границах задаётся, когда владелец их не назвал, а не когда названные оказались широкими.
93
+
94
+ Форму вопроса задают настройки владельца: где требуют меню, спрашивается меню, и к каждому
95
+ вопросу добавляется свободный вариант — у закрытого набора нет строки «вопрос не тот».
95
96
 
96
97
  **Рамка переданного текста на текущее дерево не переносится.** Передача захода, файл
97
98
  предложений и спек описывают то дерево, в котором писались. Про текущее знает только текущее:
@@ -282,15 +283,14 @@ cp docs/tasks/_template/progress.md docs/tasks/<КЛЮЧ>-<номер>-<slug>/pr
282
283
  **Следующее движение:** первый этап делается тем же ходом, а закрытым он объявляется после
283
284
  того, как прошла его команда из строки «Чем проверяется».
284
285
 
285
- ## Ловушки
286
+ ## Частые промахи
286
287
 
287
288
  - **Номер не бывает первым.** До конца разбора неизвестно даже, сколько задач из него выйдет:
288
289
  заведённая заранее задача после разбивки закрывается и остаётся мусором в очереди работ.
289
290
  - **Разбор пишется на диск сразу, а не копится в переписке.** Сессия обрывается, и разбор,
290
291
  прожитый в разговоре, восстанавливается только пересказом владельца.
291
292
  - **Из одного разбора вышло несколько задач — общее уезжает в замысел эпика.** Папка задачи
292
- умирает с мержем, а порядок задач и зависимости между ними должны его пережить. Каталог для
293
- замысла называет компаньон правила.
293
+ умирает с мержем, а порядок задач его переживает; каталог называет компаньон правила.
294
294
  - **Задача заводится командой, а не четырьмя вызовами подряд.** Борда к репозиторию не
295
295
  привязана, и задача попадает на неё только явным добавлением.
296
296
  - **Slug ветки берётся из терминологии договорённости, а не из слов просьбы.** Договорённость
@@ -58,6 +58,13 @@ const ALLOW_RENAME: boolean = process.env['E2E_ALLOW_SLUG_RENAME'] === '1';
58
58
  test.skip(!ALLOW_RENAME, 'меняет живой адрес объекта: включается E2E_ALLOW_SLUG_RENAME=1');
59
59
  ```
60
60
 
61
+ Выключатели бывают двух родов, и покрытием считается только первый. **Выключатель по состоянию
62
+ стенда** пропускает случай, которого на этом стенде не бывает по устройству, — сценарий закрыт,
63
+ и отметки он не требует. **Выключатель по переменной окружения** оставляет тест невыполненным:
64
+ сценарий за ним числится покрытым, а не проверен ничем, и такой сценарий несёт отметку
65
+ частичного покрытия с причиной. Из трёх ниже к первому роду не относится ни один: все три
66
+ управляются переменной.
67
+
61
68
  - Спека, необратимо меняющая данные стенда, по умолчанию пропускается и включается своей
62
69
  переменной.
63
70
  - `BEHIND_NGINX` в `home.smoke.spec.ts` — это `!!process.env['BASE_URL']`: вместе с ним
@@ -67,6 +74,22 @@ test.skip(!ALLOW_RENAME, 'меняет живой адрес объекта: в
67
74
  - `playwright/no-skipped-test` выключен в `eslint.config.mjs`: выключатель теста здесь —
68
75
  приём, а не забытый `test.skip`.
69
76
 
77
+ ## Код перехода проверяется ответом, а не переходом по нему
78
+
79
+ Переход браузер проходит сам, и код после него — код конечной страницы: спека, названная
80
+ «отвечает 301», утверждала 200 и не заметила бы подмены постоянного перехода на временный.
81
+ Спрашивается сам ответ, без хождения по нему:
82
+
83
+ ```ts
84
+ const answer = await request.get('/старый-адрес', { maxRedirects: 0 });
85
+
86
+ expect(answer.status()).toBe(301);
87
+ expect(answer.headers()['location']).toBe('/новый-адрес');
88
+ ```
89
+
90
+ Отличать постоянный переход от временного нужно там, где на нём стоит договорённость: поисковые
91
+ роботы и браузер запоминают только постоянный, и разница между 301 и 302 видна лишь в ответе.
92
+
70
93
  ## Частые промахи
71
94
 
72
95
  - **Порт {{ssrPort}} занимать осторожно:** стенд разработчика на {{sitePort}} ходит по тому же имени
@@ -70,7 +70,7 @@ node tools/check-turn-map.mjs # размер, полнота состояни
70
70
  без передачи, без карты, без обеих. Последний случай обязан дать пустой вывод и нулевой код —
71
71
  хук, промолчавший с ненулевым кодом, читается как отбитый запуск.
72
72
 
73
- ## Ловушки
73
+ ## Частые промахи
74
74
 
75
75
  - **Предел размера назначается замером, а не на глаз.** Первое число выбрали «вдвое больше
76
76
  нынешней карты» — и проверка покраснела на собственном тексте в первом же прогоне: карта в
@@ -26,6 +26,10 @@
26
26
  надстройка, которую она закрыла, не сопоставляются ничем, и надстройка остаётся замещать уже
27
27
  исправленный раздел.
28
28
 
29
+ Скопированная пакетная строка правится в источнике пакета, а не в копии: правка внутри
30
+ надстройки расходится с исходником молча, и видно её только там, где сам текст служит ключом
31
+ связи — в статье, у которой есть привязка. Перед правкой строки в надстройке она ищется в
32
+ источнике; не нашлась — строка своя, и правится на месте.
29
33
  - **Готовый код пакета не называет имён одного дерева.** Префикс директив кита, ключи подписей
30
34
  и имена сущностей принадлежат тому дереву, где паттерн писали; разложенные в соседнем, они
31
35
  учат звать то, чего там нет вовсе. Имя директивы при этом отличается от имени в примере: по
@@ -42,12 +46,6 @@
42
46
  отдельным шагом, отбивается как неиспользуемый ещё до того, как появится строка, которая его
43
47
  зовёт, и работа встаёт на половине. Правка делается одним вызовом либо в порядке «сначала
44
48
  использование, потом импорт».
45
- - **Прогонять сценарии гардов можно, ничего не раскладывая, — но только там, где сам пакет живёт
46
- исходниками.** Обвязка набора принимает каталог гардов переменной, и пакетную редакцию гоняют
47
- по сценариям дерева до установки. Заход, потраченный на диагноз по последствиям, стоил ровно
48
- этой строки. В поставке ни обвязки, ни каталога сценариев нет: они живут в репозитории пакета,
49
- и дерево-потребитель, поверившее совету, ищет у себя то, чего ему не отгружали.
50
-
51
49
  - **Прогонять сценарии гардов можно, ничего не раскладывая, — там, где эти сценарии есть.**
52
50
  Обвязка набора принимает каталог гардов переменной, и пакетную редакцию гоняют до установки.
53
51
  Живёт она в репозитории самого пакета: в поставку едут ресурсы, строка запуска и библиотека, а
@@ -88,3 +88,13 @@
88
88
  строки. Отличить это от применённой правки по коду возврата нечем — видно только по самому
89
89
  файлу, и обычно позже, по заголовкам собранного текста. Текст правится инструментом правки; а
90
90
  если замену всё же зовут, место, которое она обещала изменить, перечитывают сразу после неё.
91
+ - **Число, полученное командой, замером ещё не является.** Требование пересчитывать число
92
+ командой соблюдается буквально — команда была, — а мерила ли она предмет числа, не спрашивает
93
+ никто. Вывод бывает ложным по-разному и молча: `grep -E` с границей слова `\b` на BSD часть
94
+ образца игнорирует и об этом не сообщает («278 вхождений» оказались 79, и двенадцать из них о
95
+ другом), регулярка не видит, где кончается блок, и приписывает найденное соседу, а память
96
+ возвращает число, не помня его происхождения, — от замера оно неотличимо. Число пишется той
97
+ командой, которая мерит его предмет, и тем же ходом, каким пишется текст.
98
+ - **Границу слова спрашивают у той команды, которая её знает.** `grep -w`, `rg` и `python3` с
99
+ `re` её реализуют, BSD `grep -E` — нет; проверка стоит одной команды и делается до того, как
100
+ число уедет в текст.
@@ -7,6 +7,21 @@
7
7
 
8
8
  ## Ловушки
9
9
 
10
+ - **Непосчитанная сливаемость конфликтом не бывает.** Хостинг считает её заново после каждой
11
+ правки главной ветки и до конца счёта отвечает неопределённостью. Прочитанная как конфликт,
12
+ она отбивает работу на каждой свежей вершине — то есть ровно там, где отбивать нечего.
13
+ Поэтому и гард, и сверка судят только прямое «конфликтует», а молчание опроса пропускают.
14
+ - **Силовая отправка ветки, стоящей под другой в стопке, закрывает её заявку как слитую.**
15
+ Хостинг считает заявку слитой, когда вершина её ветки достижима из базы; состояние лживое — в
16
+ главной ветке правки нет, а задача остаётся открытой. Требование, из которого это следует, —
17
+ статья правила о том, что нижняя ветка череды историю не переписывает.
18
+ - **Ветка, догнанная в рабочем дереве и не отправленная, работой не считается.** Человек видит
19
+ прежнее состояние и читает его как «не сделано ничего», а сделанное лежит там, где его не
20
+ видит никто. Про неотправленный разрешённый конфликт статья правила это говорит, но догнанная
21
+ ветка без единого спора под неё не подпадает вовсе.
22
+ - **`UNKNOWN` в поле сливаемости означает «ещё не посчитано», а не «конфликтов нет».** Хостинг
23
+ считает её после каждого чужого слияния, и заявка, прочитанная в эту секунду, выглядит
24
+ здоровой.
10
25
  - **Одна работа — одна задача, сколько бы файлов она ни задела.** Числа, за которым правка
11
26
  становится второй задачей, здесь нет: делится то, что придётся откатывать порознь. Сплошная
12
27
  правка текстов дерева была заведена тремя задачами «по объёму» — пришлось стирать две,
@@ -199,3 +214,8 @@
199
214
  хостинг, заявка стоит конфликтующей при разрешённом на месте расхождении.
200
215
  - **Сверки раскладки нет в конвейере, поэтому шага, который она бы закрывала, там тоже нет.**
201
216
  Правка мимо источника в день, когда её делают, не ломает ничего.
217
+ - **Рабочее дерево не опустошается ради прогона инструмента.** Вопрос «этот долг был до моих
218
+ правок или от них» решается второй копией дерева, а не прятаньем работы: спрятанного не видит
219
+ ни статус, ни сверка, а команда, прошедшая между прятаньем и возвратом, пишет в те же файлы —
220
+ и возврат встаёт конфликтом. Так ушли в прятанье восемь незакоммиченных файлов при живом
221
+ запрете на эту команду: запрет читался в начале захода, а команда набиралась через сорок ходов.
@@ -50,3 +50,9 @@
50
50
  и число это падает по мере того, как их читают. Счёт при этом грубый: строка, показанная
51
51
  образцом внутри ограды, считается наравне с настоящей — тот, кто учит её писать, попадает
52
52
  в число объявивших.
53
+ - **Привязка пишется по тексту статьи, а не по смыслу имени гарда.** Гард, чьё имя звучит про то
54
+ же самое, статью не закрывает: статья перечисляла шесть действий по отдельному слову владельца
55
+ — коммит, пуш, открытие заявки, запись в вики, заведение задачи, правка закона, — а
56
+ поставленный ей гард не держит ни одного из них и отправки предложения среди перечисленного
57
+ нет вовсе. Читается текст статьи целиком, и в привязке называется то место, которое держит
58
+ названное ею, а не соседнее по смыслу.