@rt-tools/agent-kit 0.11.0 → 0.12.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 (115) hide show
  1. package/assets/checks/check-file-size.mjs +19 -4
  2. package/assets/checks/check-state-next.mjs +10 -2
  3. package/assets/checks/rt-kit-checks.config.mjs +16 -2
  4. package/assets/defaults/project.sh +9 -1
  5. package/assets/defaults/turn-map.md +8 -6
  6. package/assets/hooks/browser-guard-device-id.sh +3 -1
  7. package/assets/hooks/browser-guard-no-asking.sh +3 -1
  8. package/assets/hooks/browser-guard-no-other-drivers.sh +5 -3
  9. package/assets/hooks/browser-guard-require-select.sh +4 -2
  10. package/assets/hooks/claim-guard.sh +3 -1
  11. package/assets/hooks/conscience-guard.sh +3 -1
  12. package/assets/hooks/dev-server-guard.sh +5 -3
  13. package/assets/hooks/dispatch.sh +69 -0
  14. package/assets/hooks/docs-guard.sh +6 -4
  15. package/assets/hooks/exam-guard.sh +5 -3
  16. package/assets/hooks/git-guard-delivery.sh +37 -5
  17. package/assets/hooks/git-guard-main.sh +6 -4
  18. package/assets/hooks/git-guard-push-tests.sh +6 -4
  19. package/assets/hooks/grill-gate.sh +4 -2
  20. package/assets/hooks/handoff-entry-guard.sh +4 -2
  21. package/assets/hooks/handoff-write.sh +27 -6
  22. package/assets/hooks/hook-input.sh +54 -0
  23. package/assets/hooks/lint-after-edit.sh +5 -3
  24. package/assets/hooks/postmortem-guard.sh +3 -1
  25. package/assets/hooks/proposal-guard.sh +3 -1
  26. package/assets/hooks/prose-style-guard.sh +5 -3
  27. package/assets/hooks/qa-dataid-guard.sh +4 -2
  28. package/assets/hooks/rerun-guard.sh +5 -3
  29. package/assets/hooks/reuse-first-guard.sh +5 -3
  30. package/assets/hooks/rule-article.sh +99 -0
  31. package/assets/hooks/skill-gate-rearm.sh +3 -1
  32. package/assets/hooks/skill-gate.sh +23 -2
  33. package/assets/hooks/skill-loaded.sh +3 -1
  34. package/assets/hooks/sql-guard-request.sh +2 -1
  35. package/assets/hooks/sql-guard.sh +4 -2
  36. package/assets/hooks/task-flow-guard.sh +6 -4
  37. package/assets/hooks/turn-exit-guard.sh +42 -17
  38. package/assets/hooks/waiting-turn-guard.sh +3 -1
  39. package/assets/hooks/window-fill-guard.sh +6 -4
  40. package/assets/laws/work-conduct.md +5 -9
  41. package/assets/patterns/dependencies-upgrade.md +1 -1
  42. package/assets/patterns/doc-style-write.md +3 -3
  43. package/assets/patterns/git-workflow-commit.azure.md +2 -202
  44. package/assets/patterns/git-workflow-commit.github.md +2 -258
  45. package/assets/patterns/git-workflow-commit.gitlab.md +1 -217
  46. package/assets/patterns/git-workflow-docker.md +3 -3
  47. package/assets/patterns/git-workflow-merge.md +3 -2
  48. package/assets/patterns/git-workflow-migration.md +3 -3
  49. package/assets/patterns/git-workflow-pr.azure.md +224 -0
  50. package/assets/patterns/git-workflow-pr.github.md +280 -0
  51. package/assets/patterns/git-workflow-pr.gitlab.md +240 -0
  52. package/assets/patterns/git-workflow-restart.md +3 -3
  53. package/assets/patterns/git-workflow-secrets.md +3 -3
  54. package/assets/patterns/task-flow-archive.md +193 -0
  55. package/assets/patterns/task-flow-close.md +3 -173
  56. package/assets/patterns/task-flow-handoff.md +4 -4
  57. package/assets/pitfalls/doc-style.md +80 -0
  58. package/assets/pitfalls/git-workflow.azure.md +50 -0
  59. package/assets/pitfalls/git-workflow.github.md +78 -0
  60. package/assets/pitfalls/git-workflow.gitlab.md +49 -0
  61. package/assets/pitfalls/spec-driven.md +36 -0
  62. package/assets/pitfalls/styling-bem.md +45 -0
  63. package/assets/pitfalls/task-flow.md +62 -0
  64. package/assets/pitfalls/testing.md +70 -0
  65. package/assets/rules/deploy-flow.azure.md +106 -0
  66. package/assets/rules/deploy-flow.github.md +113 -0
  67. package/assets/rules/deploy-flow.gitlab.md +108 -0
  68. package/assets/rules/doc-style.md +25 -76
  69. package/assets/rules/git-workflow.azure.md +6 -92
  70. package/assets/rules/git-workflow.github.md +14 -127
  71. package/assets/rules/git-workflow.gitlab.md +6 -93
  72. package/assets/rules/spec-driven.md +39 -30
  73. package/assets/rules/styling-bem.md +20 -39
  74. package/assets/rules/task-flow.md +17 -199
  75. package/assets/rules/testing.md +3 -64
  76. package/assets/rules/turn-conduct.md +206 -0
  77. package/assets/rules/typescript-conventions.md +15 -0
  78. package/assets/skills/agent-kit.md +35 -12
  79. package/assets/templates/pitfalls.md +10 -0
  80. package/assets/templates/rule.md +5 -3
  81. package/bin/agent-kit.d.ts.map +1 -1
  82. package/bin/agent-kit.js +1 -42
  83. package/bin/agent-kit.js.map +1 -1
  84. package/lib/assets.d.ts.map +1 -1
  85. package/lib/assets.js +6 -1
  86. package/lib/assets.js.map +1 -1
  87. package/lib/cascade.d.ts.map +1 -1
  88. package/lib/cascade.js +19 -1
  89. package/lib/cascade.js.map +1 -1
  90. package/lib/commands.d.ts.map +1 -1
  91. package/lib/commands.js +1 -0
  92. package/lib/commands.js.map +1 -1
  93. package/lib/config.d.ts +16 -1
  94. package/lib/config.d.ts.map +1 -1
  95. package/lib/config.js +8 -0
  96. package/lib/config.js.map +1 -1
  97. package/lib/hooks-map.d.ts +13 -0
  98. package/lib/hooks-map.d.ts.map +1 -1
  99. package/lib/hooks-map.js +33 -1
  100. package/lib/hooks-map.js.map +1 -1
  101. package/lib/ship.d.ts +1 -2
  102. package/lib/ship.d.ts.map +1 -1
  103. package/lib/ship.js +0 -54
  104. package/lib/ship.js.map +1 -1
  105. package/package.json +1 -1
  106. package/rt-tools-agent-kit-0.12.0.tgz +0 -0
  107. package/assets/commands/agent-kit-digest.md +0 -89
  108. package/assets/commands/rules-review.md +0 -98
  109. package/assets/patterns/cargo-triage-mark.md +0 -119
  110. package/assets/rules/cargo-triage.md +0 -126
  111. package/lib/cargo-state.d.ts +0 -62
  112. package/lib/cargo-state.d.ts.map +0 -1
  113. package/lib/cargo-state.js +0 -118
  114. package/lib/cargo-state.js.map +0 -1
  115. package/rt-tools-agent-kit-0.11.0.tgz +0 -0
@@ -2,7 +2,7 @@
2
2
  name: task-flow-close
3
3
  kind: pattern
4
4
  rule: task-flow
5
- description: Паттерн правила task-flow. Брать при закрытии работы — вливание договорённости в спек домена последним коммитом PR, разбор папки задачи, переезд в архив, сверка очереди работ. Не брать для хода работы — это паттерн task-flow-resume.
5
+ description: Паттерн правила task-flow. Брать при доведении работы до готовности снятие черновика, вливание договорённости в спек домена последним коммитом PR, приведение текстов домена к сделанному. Не брать для разбора папки задачи и разбора работы правилами это паттерн task-flow-archive; не брать для хода работы — это паттерн task-flow-resume.
6
6
  ---
7
7
 
8
8
  # Закрытие работы
@@ -14,6 +14,7 @@ description: Паттерн правила task-flow. Брать при закр
14
14
 
15
15
  - Этапы замысла закрыты, проверки зелёные, с PR снимается черновик.
16
16
  - `npm run check:specs` перечислил договорённость в разделе «Пора вливать».
17
+ - Тексты домена приводятся к тому, что работа сделала.
17
18
 
18
19
  Само открытие PR сюда не относится: он открывается черновиком тем ходом, которым правка
19
20
  кода отдаётся владельцу, — то есть до этого паттерна и, как правило, задолго до него. Здесь
@@ -176,163 +177,13 @@ grep -rn -A3 "Чего из закона здесь нет" <каталог пр
176
177
  договорённость, только про это приложение.
177
178
 
178
179
  Что сделали на этом шаге, пишется в тело PR: что перечитали, что изменили, а если ничего
179
- не изменили — почему. Форма раздела — паттерн `git-workflow-commit`.
180
+ не изменили — почему. Форма раздела — паттерн `git-workflow-pr`.
180
181
 
181
182
  **Следующее движение:** приведённые тексты коммитятся, и тем же ходом разбирается папка
182
183
  задачи — последним коммитом ветки.
183
184
 
184
- ## Состояние `разбор-кончился`: папка задачи разбирается
185
-
186
- Разбор идёт по трём исходам, а не по двум.
187
-
188
- **Первым отбирается действующее требование.** Всё, что останется верным и завтра, становится
189
- статьёй закона, пунктом правила или разделом паттерна — по тому, о чём оно говорит. Признак
190
- отбора один и записан здесь заранее: перестанет ли текст быть верным, если завтра всё
191
- переделать. Перестанет — это рассказ о состоявшемся; не перестанет — требование, и место ему в
192
- слое правил. Закон при этом в ветке не правится — его статья приносится владельцу текстом.
193
-
194
- **Вторым отбирается рассказ о состоявшемся переезде.** Он уезжает в описание прошлого и
195
- называет для каждого перенесённого решения, куда оно ушло: иначе решение, ставшее правилом, и
196
- решение, потерянное при переносе, выглядят одинаково — записью, на которую никто не ссылается.
197
-
198
- **Третьим удаляется остальное.**
199
-
200
- Порядок именно такой: начав с переезда, исполнитель увозит вместе с ним и действующее — под
201
- конец работы это дешевле, чем разбирать.
202
-
203
- Целиком в архив не переносится: `docs/archive/` — место для записей о состоявшемся, которые
204
- кто-то читает, а не свалка ходов работы. Таблица ниже говорит о том, что осталось после
205
- первого отбора.
206
-
207
- | Файл | Куда |
208
- | --------------- | ------------------------------------------------------------------------------------------------------------------ |
209
- | `grill.md` | в `docs/archive/` — ответы владельца невосстановимы, и это единственная запись о том, почему задача поставлена так |
210
- | `progress.md` | в `docs/archive/`, если в нём есть решения по ходу с причинами; иначе удаляется |
211
- | `plan.md` | удаляется — после выкатки на его вопрос отвечает код, а на «как работает» отвечает спек домена |
212
- | находки разбора | переезжают к замыслу эпика — их читает владелец, когда эпик кончится; работа вне эпика показывает их сразу |
213
-
214
- Уезжающее складывается одним файлом с говорящим именем, а не папкой из трёх:
215
-
216
- ```bash
217
- cat docs/tasks/<КЛЮЧ>-<номер>-<slug>/grill.md > docs/archive/<ЧТО_РЕШАЛИ>.md
218
- rm -r docs/tasks/<КЛЮЧ>-<номер>-<slug>
219
- ```
220
-
221
- Разбор идёт в том же PR, что и работа: папка, оставленная до мержа, попадает в главную
222
- ветку и читается там как текущая.
223
-
224
- ### Работа, разбирающая чужую папку, разбирает две
225
-
226
- Своя папка у такой работы есть — она заводится наравне со всеми, исключения из этого нет. Обе
227
- снимаются последним коммитом, и порядок между ними один: сперва чужая, потом своя. Начав со
228
- своей, исполнитель теряет замысел на диске, а он ещё нужен — гард отбивает правку без него, а
229
- правка по замечаниям разбора идёт в ту же ветку.
230
-
231
- ```bash
232
- cat docs/tasks/<чужая>/grill.md > docs/archive/<ЧТО_РЕШАЛИ_ТАМ>.md
233
- rm -r docs/tasks/<чужая>
234
- cat docs/tasks/<своя>/grill.md > docs/archive/<ЧТО_РЕШАЛИ_ЗДЕСЬ>.md
235
- rm -r docs/tasks/<своя>
236
- ```
237
-
238
- Две записи в архиве, а не одна: работы разные, и решения в них разные. Сверка очереди работ
239
- после этого не называет ни одной папки — этим и проверяется, что разобраны обе.
240
-
241
- **Следующее движение:** разобранная папка уезжает в ветку тем же коммитом, и следом за ним
242
- сверяется очередь работ.
243
-
244
- ## Состояние `папка-разобрана`: сверка очереди работ
245
-
246
- ```bash
247
- npm run check:board # папка закрытой задачи среди текущих, брошенные черновики
248
- npm run check:specs # договорённость влита, привязки на месте
249
- npm run check:docs # пути, названные в текстах, существуют
250
- ```
251
-
252
- **Следующее движение:** расхождения, названные сверками, чинятся тем же ходом; чинить нечего —
253
- тот же ход снимает черновик и просит владельца влить, называя номер.
254
-
255
- ## Состояние `влито`: работа разбирается правилами — фоном, следом за PR
256
-
257
- Шаг о слое правил, а не о продукте: что за эту работу грузилось, что помогло, чего не хватило и
258
- где текст правила разошёлся с деревом. Знает это только тот заход, который работу вёл, — через
259
- сутки не знает никто.
260
-
261
- Ведёт разбор роль разбора закрытой задачи, если дерево её разложило; не разложившее ведёт его
262
- само, теми же вопросами. Файлов роль не правит — приносит готовые формулировки, а вставлять их
263
- решает владелец.
264
-
265
- **Запускается разбор в фоне, сразу за открытием PR, и ход на нём не кончается.** Роль ничего не
266
- спрашивает, пока работает, и быстрее от ожидания не идёт: следующая задача берётся тем же ходом,
267
- которым запущен разбор.
268
-
269
- Порядок один и переставлять его нельзя:
270
-
271
- 1. **Сводка собирается до запуска** — пока задача ещё в голове. Что делали, что пошло не так,
272
- что грузилось и что каждое правило дало, на какие грабли окружения наткнулись. Собранная
273
- через две задачи, она пересказывает историю ветки вместо того, что было на самом деле.
274
- 2. **Роль уходит в фон** — инструментом запуска роли, с путём к списку загруженного и сводкой
275
- целиком. Ход продолжается следующей задачей.
276
- 3. **Вернувшиеся находки принимают одним ходом** — записать и вернуться к прежнему. Разбор,
277
- отложенный «до удобного момента», не случается вовсе: заход кончается раньше.
278
-
279
- **Следующее движение:** пока роль разбирает, тот же ход занят следующей задачей; вернувшиеся
280
- находки принимаются одним ходом — записать и продолжить прежнее.
281
-
282
- ## Состояние `влито`: находки разбора ложатся в папку задачи и ждут владельца
283
-
284
- Ответ роли живёт в переписке и умирает вместе с ней, поэтому он сразу ложится на диск — в папку
285
- задачи, файлом рядом с ходом работы. Пишет его исполнитель: роль файлов не пишет.
286
-
287
- Папка задачи умирает со слиянием, а находки должны пережить весь эпик — владелец читает их
288
- разом, когда эпик кончился. Поэтому при разборе папки файл находок не удаляется вместе
289
- с остальным, а **переезжает к замыслу эпика**: там его найдут и после того, как ветка въехала.
290
- Работа вне эпика показывает находки владельцу сразу, тем же ходом.
291
-
292
- **Наружу без слова владельца уезжает только сводка наблюдений.** Она говорит, чем пользовались
293
- и чем не пользовались ни разу, — это факт, и мнением он не станет. Предложение — другое дело:
294
- это заготовка правки чужого дерева, и часть заготовок отпадает при первом же чтении. Уехавшая
295
- без разбора, она становится работой того, кто её не заказывал.
296
-
297
- Порядок такой: находки копятся у замысла эпика → эпик кончился → владелец читает их разом и
298
- говорит, что из них верно → названное им оформляется предложением и уезжает. Чем отправляют —
299
- скил слоя правил, если дерево его разложило.
300
-
301
- У каждой находки называется адрес, и адресов три:
302
-
303
- | Куда | Что туда идёт |
304
- | -------------------------- | ------------------------------------------------------------------------ |
305
- | слой правил — предложением | то, что верно любому дереву этого класса: статья, пункт правила, паттерн |
306
- | имена этого дерева | то, что верно здесь: компаньон правила, профиль, карта гейта |
307
- | надстройка над разложенным | то, что здесь звучит иначе, чем в пакете |
308
-
309
- Без адреса правка ложится туда, где её видит автор, — то есть в своё дерево, — и общее оседает
310
- в одном месте, оставаясь неизвестным всем остальным.
311
-
312
- **Разбор без правки закрытым не считается.** Из него выходит либо правка слоя правил, либо
313
- предложение наружу; не вышло ни того ни другого — это жалоба, и она повторится. Предложение, о
314
- котором владелец сказал вслух, уходит наружу в тот же ход: написанное и не отправленное лежит в
315
- дереве неотличимо от отправленного.
316
-
317
- **Следующее движение:** записанные находки работу не держат — следующая задача уже идёт, а
318
- владельцу о них говорится, когда кончился эпик.
319
-
320
185
  ## Ловушки
321
186
 
322
- - **Папку разбирают до слияния — потом о ней уже никто не вспомнит.** Сверка очереди считает
323
- задачу закрытой по слиянию: до него папка среди текущих законна, а после за неё никто не
324
- отвечает — работа перешла к следующей задаче, и находка достанется чужому заходу. Три раза
325
- подряд папка закрытой задачи так и уехала в главную ветку, в последний раз их набралось
326
- пять. Теперь это держит гард поставки: слияние отбивается, пока папка лежит в ветке.
327
- - **Разбирают последним коммитом, а не перед открытием PR.** Пока идёт ревью, замысел
328
- нужен на диске: без него правку по замечаниям не пропустит гард хода работы. Порядок такой:
329
- правки по ревью, потом разбор папки, потом слияние.
330
- - **Разбор папки идёт последним, после того как гейт пуша прошёл целиком.** Гард хода работы
331
- не пускает правку кода приложения без замысла на диске, а после разбора замысла нет: чужое
332
- замечание линтера, приехавшее мержем из главной ветки, чинить уже нечем, и гейт пуша стоит.
333
- Порядок один: мерж главной ветки, все линтеры и проверки зелёные, вливание договорённости,
334
- приведение текстов домена, разбор папки. Понадобилась правка кода после разбора — замысел
335
- восстанавливается на диске на время правки, и разбор повторяется тем же коммитом.
336
187
  - **Тексты правятся до разбора папки.** Список того, что перечитывать, лежит в замысле, а
337
188
  разбор папки его удаляет. После разбора остаётся только память о том, что задевали.
338
189
  - **Утверждение правила снимается вместе со строкой привязки.** Связь идёт по тексту
@@ -343,10 +194,6 @@ npm run check:docs # пути, названные в текстах, суще
343
194
  нет вовсе, и по слову из своей темы эта строка находилась — а неправда была в другом.
344
195
  - **Сказать «сверено», не открыв файл, нельзя.** Правило читается целиком. Устаревшее
345
196
  утверждение стоит в списке среди верных и ничем от них не отличается.
346
- - **Если папку просто удалить, первым пропадёт `grill.md`.** Удалить проще, чем разобрать, а
347
- слова владельца записаны только там, и восстановить их неоткуда. Поэтому гард требует, чтобы
348
- ветка добавила запись в архив. Что именно перенесли, он не проверяет — это смотрит владелец
349
- на ревью.
350
197
  - **Вливание после мержа не делается.** В главной ветке тогда лежит раздел «предложено, но не
351
198
  выкачено» с тем, что работает месяц, — беззвучная ложь, тем убедительнее, чем старше.
352
199
  - **Номера сценариев при вливании не пересчитываются.** Идентификатор — ключ связи с тестами;
@@ -356,22 +203,5 @@ npm run check:docs # пути, названные в текстах, суще
356
203
  стоявшее другими словами, а строка «этого раздела ещё нет» становится ложью ровно той
357
204
  работой, которая её вливает. Сверка спеков в этот раздел не смотрит вовсе. Снимается
358
205
  дословный повтор и то, что работа сделала входящим.
359
- - **Шаги закрытия с владельцем не согласуются — они перечислены здесь.** Разбор работы
360
- правилами входит в закрытие так же, как вливание договорённости и разбор папки; владелец
361
- решает не то, запускать ли его, а что делать с находками. Ход, кончившийся таким вопросом,
362
- отбивает гард разговора: за ход правила не читались, а ответ стоит в них. Спрашивается только
363
- то, чего в правилах нет.
364
- - **Блок готового кода в паттерне стареет от чужой правки.** Он не привязан ни к чему: сверка
365
- спеков читает утверждения правила, а пример под ними не читает вовсе. Два поля, ставших
366
- обязательными в чужой работе, сделали пример в соседнем паттерне несобираемым — сам он при
367
- этом не изменился ни на знак и в след задачи не попал, потому что ни одного слова той работы
368
- в нём нет. Паттерн находится по имени правленого символа, а не по теме работы.
369
206
  - **Правило без привязки в спек домена не въезжает.** Кода, который его исполняет, нет —
370
207
  значит это намерение, и место ему в открытых вопросах домена, а не в правилах.
371
- - **Замысел эпика правят только там, где вписывают «чем кончился».** Границы эпика и
372
- порядок задач в нём при этом остаются прежними, а работа их уже нарушила: задача, решившая
373
- читать спеки, оставила над собой границу «спеки — вторая очередь», и следующий исполнитель
374
- прочитает её как действующую. Границы эпика перечитываются целиком тем же заходом, что и
375
- итог работы.
376
- - **Архив не обновляется после выкатки.** Уехавшее туда описывает день переезда, и правится
377
- оно только вместе с признанием, что описывало неверно.
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: task-flow-handoff
3
3
  kind: pattern
4
- rule: task-flow
5
- description: Паттерн правила task-flow. Брать, когда заход упирается в заполнение окна — выбор точки остановки, запись хода работы, форма передачи и что владелец с ней делает. Не брать для возвращения к работе новым заходом — это паттерн task-flow-resume.
4
+ rule: turn-conduct
5
+ description: Паттерн правила turn-conduct. Брать, когда заход упирается в заполнение окна — выбор точки остановки, запись хода работы, форма передачи и что владелец с ней делает. Не брать для возвращения к работе новым заходом — это паттерн task-flow-resume.
6
6
  ---
7
7
 
8
8
  # Закрытие захода по заполнению окна
9
9
 
10
- Паттерн правила `task-flow`. Что при этом должно быть верно — закон
10
+ Паттерн правила `turn-conduct`. Что при этом должно быть верно — закон
11
11
  `docs/constitution/work-conduct.md`.
12
12
 
13
13
  ## Когда брать
@@ -55,7 +55,7 @@ description: Паттерн правила task-flow. Брать, когда з
55
55
  ### Коммит
56
56
 
57
57
  Проверенное коммитится сразу, а не копится до конца задачи. Работа кончена — открывается PR:
58
- паттерн `git-workflow-commit`.
58
+ паттерн `git-workflow-pr`.
59
59
 
60
60
  ### Передача
61
61
 
@@ -0,0 +1,80 @@
1
+ # Тексты проекта — холодная часть
2
+
3
+ Ловушки: грабли, на которые уже наступали. Грузится не вместе с правилом, а по
4
+ требованию — при обычном решении она не нужна.
5
+
6
+ Правило — `doc-style`; статьи, которыми держится закон, стоят там.
7
+
8
+ ## Ловушки
9
+
10
+ - **Оставшаяся работа не записывается в документ, а заводится задачей.** `docs/BACKLOG.md`
11
+ держит только то, что задачей не бывает: договорённости и решения, которые решено не
12
+ править. Признак — утверждение остаётся, если править его никто не собирается. «Сделать
13
+ потом» в плане, README или спеке — второй список работ: он расходится с бордой молча, а
14
+ разбирать его потом дороже, чем завести задачу сразу. Из 1411 строк документа действующими
15
+ оказались 71, и на разбор остальных ушла отдельная задача. Как разбирать накопившееся —
16
+ паттерн `doc-style-sweep`.
17
+ - **Словарь действует и на разговор с владельцем, не только на файлы.** Он приходит в контекст
18
+ на запуске сессии, поэтому «не читал» основанием не бывает. Слово из левой колонки «Так не
19
+ пишем» всплывало именно в ответах: в дереве его уже вычистили, а в PR о сделанном оно
20
+ оставалось, и владелец читал ровно то слово, от которого отказались.
21
+ - **Термин берётся из `docs/GLOSSARY.md`, а не придумывается на месте.** Слова, которого там
22
+ нет, у читателя нет тоже: «журнал приложения» простоял в спеке почты, пока владелец не
23
+ спросил, что это, — оказалось, логи бэкенда, а слово «журнал» здесь уже занято журналом
24
+ событий. Новое слово либо заводится в словаре вместе с правкой, либо заменяется тем, что
25
+ уже есть.
26
+ - **Проход по словарю глазами слово не находит.** «Формулировки приведены к словарю» означает
27
+ ровно те строки, которые в тот момент читали: «спека» пережила такой проход и осталась в
28
+ соседней строке того же файла. Слово из левой колонки таблицы «Так не пишем» вычищается
29
+ грепом по всему дереву, а не вычиткой. Форма задаётся точно: «спек» — документ — склоняется
30
+ в «спека» и «спеки» тоже, и совпадений по корню законных больше, чем нарушений; ищутся
31
+ сочетания («спеки на … нет», «спека проверяет»), а не корень.
32
+ - **Снятое имя вычищается одним грепом по всему дереву:** правила, их зеркала в скилах,
33
+ документы и комментарии. Описание того, чего в коде уже нет, читается как действующее
34
+ указание.
35
+ - **У снятого слова второе значение возвращается после сплошной замены, а не обходится до
36
+ неё.** Слово снимают ровно потому, что оно стояло над двумя вещами, и второе значение при
37
+ этом остаётся законным. Отобрать его заранее нечем: какое из двух значений в строке, видно
38
+ только по соседнему тексту, а строк бывают сотни. Порядок обратный — сплошная замена, затем
39
+ сплошной просмотр самой правки, и найденное второе значение возвращается поимённо. Из 353
40
+ замен так вернулись шесть, и две первые были поломкой: сверка печатала новое имя дважды
41
+ подряд, а комментарий обещал «поломку вместо PR о том, что долгов нет». Просматривается
42
+ правка, а не дерево после неё: в дереве обе стороны выглядят одинаково верными.
43
+ - **Поиск по дереву не покрывает того, что уже уехало наружу.** Заголовок задачи и её тело,
44
+ заголовок PR и его тело, заголовки коммитов лежат вне файлов, и проверки текстов их не
45
+ читают вовсе. Вычистив слово в дереве, обходят те же места в очереди работ и в истории:
46
+
47
+ ```bash
48
+ <клиент хостинга> api "<путь к PR>" --jq '.title, .body' | grep -i '<слово>'
49
+ <клиент хостинга> api "<путь к задаче>" --jq '.title, .body' | grep -i '<слово>'
50
+ git log --format='%s%n%b' <база>..HEAD | grep -i '<слово>'
51
+ ```
52
+
53
+ Заголовок PR правится вызовом хостинга, заголовок коммита — только переписыванием ветки,
54
+ поэтому его проверяют до пуша. Выдуманное слово было вычищено из трёх файлов и объявлено
55
+ снятым, а в заголовке PR и в заголовке коммита осталось — владелец прочитал именно его.
56
+
57
+ - **Число в тексте пересчитывается командой в том же коммите, где пишется.** Оно стареет
58
+ внутри одной ветки: «шестнадцать пар» стало неправдой через два коммита после того, как
59
+ было написано, и нашёл это владелец, а не проверка. Число, которое придётся пересчитывать
60
+ при каждой правке, лучше не писать вовсе. Число, полученное разбором текста, сверяется на
61
+ выборке руками до того, как его называют: разбор, не знающий второй формы записи, ошибается
62
+ молча — «51 пункт без задачи» оказался шестью, потому что номер стоял и отдельной строкой, и
63
+ в заголовке подраздела.
64
+ - **Названная в тексте проверка запускается, а не пересказывается.** «Проверка есть» и
65
+ «проверка проходит» — разные утверждения, и второго в тексте обычно нет вовсе. Из четырёх
66
+ проверок, названных правилом, три оказались не в том состоянии, в каком текст их описывает:
67
+ одна отдавала полтора десятка замечаний, вторая переписывала файлы самим запуском, третья
68
+ была красной и роняла общую сводку вместе с собой. Ни одна из трёх не входила в выкатку,
69
+ поэтому молчание было полным. Проверку, которая переписывает файлы, запускают на чистом
70
+ дереве: иначе её правки уедут чужим коммитом.
71
+ - **Сделанность читается по дереву, а не по тексту, который о ней написан.** Это верно в обе
72
+ стороны: строка про README обеих либ была вычеркнута как сделанная, а README остался с
73
+ прежним числом импортёров; задача, названная владельцу несделанной, оказалась наполовину
74
+ закрытой и покрытой сценариями хука. Пункт плана и тело задачи описывают день, когда их
75
+ написали, и с тех пор не менялись.
76
+ - **Комментарий в файле — такое же утверждение, как строка в документе.** Обоснование «строки
77
+ идут во всю ширину панели, иначе подсветка обрывается» было выдумано, прожило три сессии и
78
+ каждый раз читалось как основание вёрстку не трогать.
79
+ - **Чужие проекты не упоминаются нигде** — ни имени репозитория, ни «портировано из», ни
80
+ ссылок на его файлы. Описывается то, что код делает здесь, в терминах этого проекта.
@@ -0,0 +1,50 @@
1
+ # Поставка — холодная часть
2
+
3
+ Ловушки: грабли, на которые уже наступали в дереве на Azure DevOps. Грузится не вместе с
4
+ правилом, а по требованию — при обычном решении она не нужна.
5
+
6
+ Правило — `git-workflow`; статьи, которыми держится закон, стоят там.
7
+
8
+ ## Ловушки
9
+
10
+ - **Одна работа — одна задача, сколько бы файлов она ни задела.** Числа, за которым правка
11
+ становится вторым рабочим элементом, здесь нет: делится то, что придётся откатывать порознь.
12
+ Сплошная правка текстов дерева была заведена тремя задачами «по объёму» — пришлось стирать
13
+ два рабочих элемента, закрывать два PR и переносить коммиты по одному с двумя конфликтами.
14
+ Одна из трёх не дала коммита вовсе: правка тел уже заведённых задач веткой не бывает и задачей
15
+ под ветку тоже.
16
+ - **Рабочий элемент заводится командой, а не вызовами подряд.** Доска показывает элементы своей
17
+ области и итерации, и заведённый мимо них в очереди работ не виден: со стороны это выглядит
18
+ так же, как незаведённый. Команда заведения ставит все поля разом — род, состояние,
19
+ исполнителя, область и итерацию, — и печатает готовую строку заведения ветки. Замеченный по
20
+ ходу дефект проходит тот же путь.
21
+ - **Ветка заводится вторым вызовом, а не тем же.** Гард главной ветки отклоняет составную
22
+ «создать ветку и сразу коммитить» целиком: ветки в момент разбора ещё нет.
23
+ - **Сторона конфликта бывает удалением, и «сохранить обе стороны» заводит второе объявление.**
24
+ Главная ветка снимает объявление, потому что символ переехал, — в конфликте это выглядит как
25
+ сторона, которая ничего не дописала. Разбирается чтением версии главной ветки целиком, а не по
26
+ хунку, и сверяется проверкой повторов: обе копии сами по себе исправны, сборка и линт зелёные.
27
+ - **Учётная запись для пуша и автор PR выбираются отдельно.** Если пушить пришлось из-под другой
28
+ записи, на следующий вызов это не переносится: PR открывают токеном учётной записи машинной
29
+ работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
30
+ смена записи ради пуша утекла в публикацию — PR вышел от владельца.
31
+ - **Невалидный файл конвейера виден прогоном нулевой длительности сразу после пуша.** Прогон
32
+ заводится и кончается на разборе файла, не начав ни одного задания: в списке он стоит
33
+ отказом, а внутри нет ни задания, ни лога — читается только длительность. Поэтому список
34
+ прогонов ветки смотрится тем же движением, что и пуш: `az pipelines runs list` по своей
35
+ ветке.
36
+ - **`online` у агента на своей машине означает запущенный процесс, а не работающий конвейер.**
37
+ Две стороны сходятся отдельно: требования заданий и возможности самого агента в его пуле.
38
+ Пока пересечения нет, агент стоит `online` и не берёт ничего, а задания ждут размещённого
39
+ пула — по состоянию это выглядит настроенным. Владельцу называют выполненное задание с его
40
+ номером, а не строку состояния.
41
+ - **Вход в реестр образов из агента, запущенного службой, отказывает молча.** Служба идёт без
42
+ сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
43
+ отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
44
+ не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
45
+ `git-workflow-docker`.
46
+ - **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
47
+ разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
48
+ входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
49
+ которому нужен ключ. Что именно переносится руками, названо списком в компаньоне правила, и
50
+ список пополняется тем же движением, которым заводится новый файл вне индекса.
@@ -0,0 +1,78 @@
1
+ # Поставка — холодная часть
2
+
3
+ Ловушки: грабли, на которые уже наступали в дереве на GitHub. Грузится не вместе с
4
+ правилом, а по требованию — при обычном решении она не нужна.
5
+
6
+ Правило — `git-workflow`; статьи, которыми держится закон, стоят там.
7
+
8
+ ## Ловушки
9
+
10
+ - **Одна работа — одна задача, сколько бы файлов она ни задела.** Числа, за которым правка
11
+ становится второй задачей, здесь нет: делится то, что придётся откатывать порознь. Сплошная
12
+ правка текстов дерева была заведена тремя задачами «по объёму» — пришлось стирать две,
13
+ закрывать два PR и переносить коммиты по одному с двумя конфликтами. Одна из трёх не дала
14
+ коммита вовсе: правка тел уже заведённых задач веткой не бывает и задачей под ветку тоже.
15
+ - **Задача заводится командой, а не четырьмя вызовами подряд.** Борда к репозиторию не
16
+ привязана, и задача попадает на неё только явным добавлением: две задачи так и простояли вне
17
+ очереди работ, потому что шаг переписывали руками. Команда заведения делает все четыре — issue,
18
+ номер в его заголовке, добавление на борду, начальную колонку, — и печатает готовую строку
19
+ заведения ветки. Замеченный по ходу дефект проходит тот же путь.
20
+ - **Ветка заводится вторым вызовом, а не тем же.** Гард главной ветки отклоняет составную
21
+ «создать ветку и сразу коммитить» целиком: ветки в момент разбора ещё нет.
22
+ - **Сторона конфликта бывает удалением, и «сохранить обе стороны» заводит второе объявление.**
23
+ Главная ветка снимает объявление, потому что символ переехал, — в конфликте это выглядит как
24
+ сторона, которая ничего не дописала. Разбирается чтением версии главной ветки целиком, а не по
25
+ хунку, и сверяется проверкой повторов: обе копии сами по себе исправны, сборка и линт зелёные.
26
+ - **Учётная запись для пуша и автор PR выбираются отдельно.** Если пушить пришлось из-под другой
27
+ записи, на следующий вызов это не переносится: PR открывают токеном учётной записи машинной
28
+ работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
29
+ смена записи ради пуша утекла в публикацию — PR вышел от владельца. Разница между читающим и
30
+ пишущим вызовом в самом тексте команды не видна: личность приходит окружением, поэтому у
31
+ вызова на запись токен называется явно, а открытая заявка проверяется ответом хостинга о её
32
+ авторе — напечатанная ссылка говорит, что заявка создана, и молчит о том, кем. Чинится это
33
+ только переоткрытием: автора у заявки не сменить.
34
+ - **Невалидный файл конвейера виден прогоном нулевой длительности сразу после пуша.** GitHub
35
+ заводит такой прогон и на ветке, на которую ни один триггер не подписан: в списке он стоит
36
+ отказом, а внутри у него нет ни задания, ни лога — читается только длительность. Поэтому
37
+ список прогонов ветки смотрится тем же движением, что и пуш — `gh run list --branch <ветка>`.
38
+ Один такой отказ простоял в списке до мержа, и на него никто не посмотрел: выкатка после
39
+ мержа отказала ровно тем же.
40
+ - **Прогон, не вставший на пуш, возвращается повтором события, а не разбором ветки.** Замером
41
+ проверены обе законные дороги: и открытие PR, и пуш в уже открытый PR прогон заводят —
42
+ текстовый коммит и учётная запись, которой пушат, тут ни при чём. Пропавшие события пришлись
43
+ на час, когда хостинг отвечал `429` на загрузке действия и `503` на API, а списком прогонов
44
+ «не завёлся» от «не создан» не отличить. Поэтому вершину без прогона называет сверка очереди
45
+ работ, а событие возвращается новым коммитом либо перезакрытием PR.
46
+ - **Красное на шаге подготовки задания — отказ хостинга, а не дефект ветки.** Раннер не смог
47
+ скачать действие чекаута и получил `429 Too Many Requests`; до кода прогон при этом не дошёл
48
+ вовсе. Лечится перезапуском прогона, и от красного по существу отличается тем, на каком шаге
49
+ оно встало: три прогона одного дня упали именно так.
50
+ - **Контекст `runner` в `env` задания отбивает весь файл конвейера.** Там доступны только
51
+ `github`, `needs`, `strategy`, `matrix`, `vars`, `secrets` и `inputs`; `runner` появляется на
52
+ уровне шага, где то же значение приходит переменной окружения. Такой файл не принимается
53
+ вовсе: прогон кончается за ноль секунд, не начав ни одного задания. Разбор YAML этого не
54
+ ловит — синтаксис верный, а доступность контекстов синтаксисом не является.
55
+ - **`online` у раннера на своей машине означает запущенный процесс, а не работающий
56
+ конвейер.** Две стороны сходятся отдельно: `runs-on` у заданий и метки самого раннера. Пока
57
+ пересечения нет, раннер стоит `online` и не берёт ничего, а задания уходят в облако — по
58
+ состоянию это выглядит настроенным. Владельцу называют выполненное задание с его номером, а
59
+ не строку состояния.
60
+ - **Раннер на своей машине делает прогон общим ресурсом, и стенд у прогонов один.** Порт,
61
+ имя базы и каталог сборки зашиты в дереве одним значением на всех: два прогона разом
62
+ поднимают два стенда на один порт, и второй падает целиком. Дороже всего не падение, а его
63
+ вид — в отчёте оно выглядит десятком красных спек про экраны, то есть дефектом правки,
64
+ которого нет; три прогона подряд так и упали на трёх ветках, не тронувших кода. Лечится с
65
+ двух сторон сразу: конвейеру объявляется группа очереди на всё дерево, а имена стенда
66
+ читаются из окружения с нынешними значениями в умолчании — иначе прогон и гейт пуша, зовущий
67
+ ту же команду, столкнутся и при очереди. Одной очереди мало, одних имён — тоже: прогоны делят
68
+ ещё диск, кэш сборщика и демон образов.
69
+ - **Вход в реестр образов из раннера, запущенного службой, отказывает молча.** Служба идёт без
70
+ сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
71
+ отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
72
+ не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
73
+ `git-workflow-docker`.
74
+ - **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
75
+ разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
76
+ входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
77
+ которому нужен ключ. Что именно переносится руками, названо списком в компаньоне правила, и
78
+ список пополняется тем же движением, которым заводится новый файл вне индекса.
@@ -0,0 +1,49 @@
1
+ # Поставка — холодная часть
2
+
3
+ Ловушки: грабли, на которые уже наступали в дереве на GitLab. Грузится не вместе с
4
+ правилом, а по требованию — при обычном решении она не нужна.
5
+
6
+ Правило — `git-workflow`; статьи, которыми держится закон, стоят там.
7
+
8
+ ## Ловушки
9
+
10
+ - **Одна работа — одна задача, сколько бы файлов она ни задела.** Числа, за которым правка
11
+ становится второй задачей, здесь нет: делится то, что придётся откатывать порознь. Сплошная
12
+ правка текстов дерева была заведена тремя задачами «по объёму» — пришлось стирать две,
13
+ закрывать два MR и переносить коммиты по одному с двумя конфликтами. Одна из трёх не дала
14
+ коммита вовсе: правка тел уже заведённых задач веткой не бывает и задачей под ветку тоже.
15
+ - **Задача заводится командой, а не вызовами подряд.** Доска показывает те issue, чью метку
16
+ знает, и задача без метки списка в очереди работ не видна: со стороны это выглядит так же, как
17
+ незаведённая. Команда заведения ставит всё разом — issue, номер в его заголовке, метку списка,
18
+ исполнителя, — и печатает готовую строку заведения ветки. Замеченный по ходу дефект проходит
19
+ тот же путь.
20
+ - **Ветка заводится вторым вызовом, а не тем же.** Гард главной ветки отклоняет составную
21
+ «создать ветку и сразу коммитить» целиком: ветки в момент разбора ещё нет.
22
+ - **Сторона конфликта бывает удалением, и «сохранить обе стороны» заводит второе объявление.**
23
+ Главная ветка снимает объявление, потому что символ переехал, — в конфликте это выглядит как
24
+ сторона, которая ничего не дописала. Разбирается чтением версии главной ветки целиком, а не по
25
+ хунку, и сверяется проверкой повторов: обе копии сами по себе исправны, сборка и линт зелёные.
26
+ - **Учётная запись для пуша и автор MR выбираются отдельно.** Если пушить пришлось из-под другой
27
+ записи, на следующий вызов это не переносится: MR открывают токеном учётной записи машинной
28
+ работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
29
+ смена записи ради пуша утекла в публикацию — PR вышел от владельца.
30
+ - **Невалидный файл конвейера виден отказом сразу после пуша, а не упавшим заданием.** Конвейер
31
+ на такой файл не заводится вовсе: в списке стоит запись об ошибке разбора, а внутри нет ни
32
+ задания, ни лога. Поэтому список конвейеров ветки смотрится тем же движением, что и пуш —
33
+ `glab ci list --branch <ветка>`, — а сам файл до пуша судит проверка `.gitlab-ci.yml` в
34
+ проекте.
35
+ - **`online` у раннера на своей машине означает запущенный процесс, а не работающий
36
+ конвейер.** Две стороны сходятся отдельно: `tags` у заданий и теги самого раннера. Пока
37
+ пересечения нет, раннер стоит `online` и не берёт ничего, а задания ждут общего раннера — по
38
+ состоянию это выглядит настроенным. Владельцу называют выполненное задание с его номером, а
39
+ не строку состояния.
40
+ - **Вход в реестр образов из раннера, запущенного службой, отказывает молча.** Служба идёт без
41
+ сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
42
+ отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
43
+ не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
44
+ `git-workflow-docker`.
45
+ - **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
46
+ разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
47
+ входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
48
+ которому нужен ключ. Что именно переносится руками, названо списком в компаньоне правила, и
49
+ список пополняется тем же движением, которым заводится новый файл вне индекса.
@@ -0,0 +1,36 @@
1
+ # Документация проекта — холодная часть
2
+
3
+ Ловушки: грабли, на которые уже наступали. Грузится не вместе с правилом, а по
4
+ требованию — при обычном решении она не нужна.
5
+
6
+ Правило — `spec-driven`; статьи, которыми держится закон, стоят там.
7
+
8
+ ## Ловушки
9
+
10
+ - **`tasks.md` в спеке не заводить.** Шаги — артефакт сессии, им место в ветке или в описании
11
+ PR. Как только в директории появляются «шаги», спек снова становится планом и умирает после
12
+ мержа.
13
+ - **Спек описывает установившееся, а не предстоящее.** Единственное место, где он говорит о
14
+ будущем, — `proposed/<фича>/`. После выкатки его текст вливается в спек домена, директория
15
+ удаляется, идентификаторы сценариев не меняются.
16
+ - **Семантику полей не сверяет ничто.** Проверка знает имена процедур, коды отказа и связь
17
+ сценариев с тестами; что означает пустое поле — не знает. Правка `.proto` поэтому тянет
18
+ спеки всех доменов, чьи процедуры она задела, в той же ветке.
19
+ - **Живость символа считается совпадением имени по всему дереву, а не вызовом.** Символу
20
+ хватает второго упоминания где угодно — в чужом поле с тем же именем, в атрибуте разметки.
21
+ Место, где правило исполняется на самом деле, подтверждается только чтением кода.
22
+ - **Якорь в `tools/*.mjs` сверяется почти ничем:** живость считается только для `.ts`, а
23
+ исходники обходятся по `apps`, `libs` и `prisma`. Правило, привязанное к проверке, поэтому
24
+ читается вместе с её телом.
25
+ - **Зелёная проверка не значит, что структура верна.** Спутники с привязкой сначала лежали
26
+ рядом с законами, и проверка была зелёной именно потому, что структура совпадала с тем,
27
+ чего проверка сама и ждала.
28
+ - **Конфликт мержа в спеке разрешается сохранением обеих сторон, а не выбором одной.** Две
29
+ ветки дописывают в конец одних и тех же списков — сценариев, правил, строк привязки, — и
30
+ обе стороны верны: конфликт здесь не спор, а две дописи в одно место. Номера сценариев при
31
+ разрешении не пересчитываются: идентификатор — ключ связи с тестами, и сдвиг номеров рвёт
32
+ сверку у соседей, которых правка не касалась. Порядок сохранённых сторон держится
33
+ одинаковым в `spec.md`, `scenarios.md` и `implementation.md`: иначе правило, его сценарий и
34
+ его привязка перестают находиться друг по другу. После разрешения гоняется
35
+ `npm run check:specs` — конфликт в спеке кода не задевает, и ни сборка, ни линтеры его не
36
+ увидят.