@rt-tools/agent-kit 0.2.0 → 0.4.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 (203) hide show
  1. package/README.md +235 -18
  2. package/assets/agents/business-analyst.md +74 -0
  3. package/assets/agents/project-manager.md +70 -0
  4. package/assets/agents/qa-engineer.md +72 -0
  5. package/assets/agents/skill-curator.md +110 -0
  6. package/assets/agents/spec-critic.md +44 -0
  7. package/assets/agents/spec-writer.md +50 -0
  8. package/assets/checks/board.github.mjs +286 -0
  9. package/assets/checks/check-board.github.mjs +188 -0
  10. package/assets/checks/check-doc-paths.mjs +163 -0
  11. package/assets/checks/check-dupes.mjs +277 -0
  12. package/assets/checks/check-lib-layers.mjs +573 -0
  13. package/assets/checks/check-reuse.mjs +208 -0
  14. package/assets/checks/check-schema-drift.mjs +186 -0
  15. package/assets/checks/check-specs.mjs +1007 -0
  16. package/assets/checks/check-styles.mjs +109 -0
  17. package/assets/checks/rt-kit-checks.config.mjs +134 -0
  18. package/assets/checks/task-new.github.mjs +198 -0
  19. package/assets/commands/skill-curator.md +70 -0
  20. package/assets/defaults/gate-map.sh +100 -0
  21. package/assets/defaults/project.sh +179 -0
  22. package/assets/hooks/browser-device-id.sh +20 -0
  23. package/assets/hooks/browser-guard-device-id.sh +28 -0
  24. package/assets/hooks/browser-guard-no-asking.sh +27 -0
  25. package/assets/hooks/browser-guard-no-listing.sh +18 -0
  26. package/assets/hooks/browser-guard-no-other-drivers.sh +79 -0
  27. package/assets/hooks/browser-guard-require-select.sh +54 -0
  28. package/assets/hooks/commit-msg.sh +26 -0
  29. package/assets/hooks/constitution-index.sh +43 -0
  30. package/assets/hooks/dev-server-guard.sh +115 -0
  31. package/assets/hooks/docs-guard.sh +282 -0
  32. package/assets/hooks/git-guard-delivery.sh +167 -0
  33. package/assets/hooks/git-guard-main.sh +73 -0
  34. package/assets/hooks/git-guard-push-tests.sh +94 -0
  35. package/assets/hooks/glossary-load.sh +23 -0
  36. package/assets/hooks/lint-after-edit.sh +219 -0
  37. package/assets/hooks/qa-dataid-guard.sh +121 -0
  38. package/assets/hooks/reuse-first-guard.sh +154 -0
  39. package/assets/hooks/skill-gate-rearm.sh +23 -0
  40. package/assets/hooks/skill-gate.sh +128 -0
  41. package/assets/hooks/skill-loaded.sh +21 -0
  42. package/assets/hooks/sql-guard.sh +679 -0
  43. package/assets/hooks/task-context-load.sh +100 -0
  44. package/assets/hooks/task-flow-guard.sh +107 -0
  45. package/assets/laws/{access.md → application/access.md} +1 -4
  46. package/assets/laws/{locales.md → application/locales.md} +1 -3
  47. package/assets/laws/application/money.md +41 -0
  48. package/assets/laws/application/ownership.md +32 -0
  49. package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
  50. package/assets/laws/code-structure.md +7 -6
  51. package/assets/laws/delivery.md +53 -3
  52. package/assets/laws/entity-editing.md +49 -55
  53. package/assets/laws/entity-models.md +4 -14
  54. package/assets/laws/frontend-application.md +5 -5
  55. package/assets/laws/lib-imports.md +14 -1
  56. package/assets/laws/lists.md +33 -0
  57. package/assets/laws/navigation.md +40 -0
  58. package/assets/laws/project-documentation.md +17 -8
  59. package/assets/laws/reuse-first.md +26 -21
  60. package/assets/laws/shared-code.md +13 -1
  61. package/assets/laws/verifiability.md +17 -1
  62. package/assets/laws/work-conduct.md +48 -0
  63. package/assets/patterns/admin-lists-screen.md +131 -0
  64. package/assets/patterns/admin-nav-item.md +71 -0
  65. package/assets/patterns/angular-patterns-state.md +101 -0
  66. package/assets/patterns/api-layer-pair.md +88 -0
  67. package/assets/patterns/browser-verification-measure.md +86 -0
  68. package/assets/patterns/browser-verification-stand.md +143 -0
  69. package/assets/patterns/component-structure-new.md +99 -0
  70. package/assets/patterns/dependencies-upgrade.md +65 -0
  71. package/assets/patterns/doc-style-sweep.md +137 -0
  72. package/assets/patterns/doc-style-write.md +109 -0
  73. package/assets/patterns/entity-aside.md +136 -0
  74. package/assets/patterns/entity-models-new.md +124 -0
  75. package/assets/patterns/entity-store.md +91 -0
  76. package/assets/patterns/git-workflow-commit.azure.md +259 -0
  77. package/assets/patterns/git-workflow-commit.github.md +333 -0
  78. package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
  79. package/assets/patterns/git-workflow-merge.md +99 -0
  80. package/assets/patterns/git-workflow-migration.md +88 -0
  81. package/assets/patterns/git-workflow-restart.md +49 -0
  82. package/assets/patterns/lib-layers-move.md +95 -0
  83. package/assets/patterns/lib-layers-new.md +82 -0
  84. package/assets/patterns/ownership-scope-resolve.md +69 -0
  85. package/assets/patterns/permissions-procedure.md +71 -0
  86. package/assets/patterns/platform-access-di.md +84 -0
  87. package/assets/patterns/pricing-quote.md +71 -0
  88. package/assets/patterns/reuse-first-extend.md +73 -0
  89. package/assets/patterns/seo-page.md +104 -0
  90. package/assets/patterns/seo-verify.md +83 -0
  91. package/assets/patterns/shared-code-new.md +86 -0
  92. package/assets/patterns/spec-driven-domain.md +107 -0
  93. package/assets/patterns/spec-driven-rule.md +127 -0
  94. package/assets/patterns/styling-bem-component.md +88 -0
  95. package/assets/patterns/styling-bem-layout.md +73 -0
  96. package/assets/patterns/task-flow-close.md +90 -0
  97. package/assets/patterns/task-flow-resume.md +94 -0
  98. package/assets/patterns/task-flow-start.md +117 -0
  99. package/assets/patterns/testing-e2e.md +92 -0
  100. package/assets/patterns/testing-unit.md +117 -0
  101. package/assets/patterns/translations-key.md +64 -0
  102. package/assets/patterns/ts-procedure.md +65 -0
  103. package/assets/rules/angular-patterns.md +71 -0
  104. package/assets/rules/api-layer.md +71 -0
  105. package/assets/rules/browser-verification.md +87 -0
  106. package/assets/rules/component-structure.md +64 -0
  107. package/assets/rules/dependencies.md +66 -0
  108. package/assets/rules/doc-style.md +103 -0
  109. package/assets/rules/entity-conventions.md +78 -0
  110. package/assets/rules/entity-models.md +70 -0
  111. package/assets/rules/git-workflow.azure.md +116 -0
  112. package/assets/rules/git-workflow.github.md +123 -0
  113. package/assets/rules/git-workflow.gitlab.md +113 -0
  114. package/assets/rules/lib-layers.md +80 -0
  115. package/assets/rules/lists.md +73 -0
  116. package/assets/rules/navigation.md +78 -0
  117. package/assets/rules/ownership-scope.md +63 -0
  118. package/assets/rules/permissions.md +70 -0
  119. package/assets/rules/platform-access.md +77 -0
  120. package/assets/rules/pricing.md +64 -0
  121. package/assets/rules/reuse-first.md +83 -0
  122. package/assets/rules/seo.md +71 -0
  123. package/assets/rules/shared-code.md +70 -0
  124. package/assets/rules/spec-driven.md +135 -0
  125. package/assets/rules/styling-bem.md +74 -0
  126. package/assets/rules/task-flow.md +110 -0
  127. package/assets/rules/testing.md +100 -0
  128. package/assets/rules/translations.md +69 -0
  129. package/assets/rules/typescript-conventions.md +76 -0
  130. package/assets/skills/agent-kit.md +81 -0
  131. package/assets/skills/write-a-skill.md +108 -0
  132. package/assets/templates/gate-map.sh +45 -0
  133. package/assets/templates/implementation.md +44 -0
  134. package/assets/templates/pattern.md +5 -1
  135. package/assets/templates/project.sh +54 -0
  136. package/assets/templates/rule.md +12 -23
  137. package/assets/variants.json +20 -0
  138. package/assets/workflows/feature.js +134 -0
  139. package/assets/workflows/plan.js +150 -0
  140. package/bin/agent-kit.d.ts.map +1 -1
  141. package/bin/agent-kit.js +78 -5
  142. package/bin/agent-kit.js.map +1 -1
  143. package/bin/prompt.d.ts +5 -0
  144. package/bin/prompt.d.ts.map +1 -1
  145. package/bin/prompt.js +19 -7
  146. package/bin/prompt.js.map +1 -1
  147. package/index.d.ts +1 -0
  148. package/index.d.ts.map +1 -1
  149. package/index.js +1 -0
  150. package/index.js.map +1 -1
  151. package/lib/assets.d.ts +14 -1
  152. package/lib/assets.d.ts.map +1 -1
  153. package/lib/assets.js +23 -2
  154. package/lib/assets.js.map +1 -1
  155. package/lib/catalog.d.ts +52 -5
  156. package/lib/catalog.d.ts.map +1 -1
  157. package/lib/catalog.js +104 -16
  158. package/lib/catalog.js.map +1 -1
  159. package/lib/commands.d.ts +22 -1
  160. package/lib/commands.d.ts.map +1 -1
  161. package/lib/commands.js +218 -11
  162. package/lib/commands.js.map +1 -1
  163. package/lib/companion.d.ts +57 -0
  164. package/lib/companion.d.ts.map +1 -0
  165. package/lib/companion.js +60 -0
  166. package/lib/companion.js.map +1 -0
  167. package/lib/config.d.ts +42 -2
  168. package/lib/config.d.ts.map +1 -1
  169. package/lib/config.js +60 -2
  170. package/lib/config.js.map +1 -1
  171. package/lib/freshness.d.ts +14 -0
  172. package/lib/freshness.d.ts.map +1 -0
  173. package/lib/freshness.js +116 -0
  174. package/lib/freshness.js.map +1 -0
  175. package/lib/hooks-map.d.ts +24 -0
  176. package/lib/hooks-map.d.ts.map +1 -0
  177. package/lib/hooks-map.js +72 -0
  178. package/lib/hooks-map.js.map +1 -0
  179. package/lib/integrity.d.ts +36 -0
  180. package/lib/integrity.d.ts.map +1 -0
  181. package/lib/integrity.js +44 -0
  182. package/lib/integrity.js.map +1 -0
  183. package/lib/picker.d.ts +11 -1
  184. package/lib/picker.d.ts.map +1 -1
  185. package/lib/picker.js +44 -6
  186. package/lib/picker.js.map +1 -1
  187. package/lib/stamp.d.ts +2 -5
  188. package/lib/stamp.d.ts.map +1 -1
  189. package/lib/stamp.js +25 -10
  190. package/lib/stamp.js.map +1 -1
  191. package/lib/sync.d.ts +29 -0
  192. package/lib/sync.d.ts.map +1 -1
  193. package/lib/sync.js +78 -4
  194. package/lib/sync.js.map +1 -1
  195. package/lib/variants.d.ts +44 -0
  196. package/lib/variants.d.ts.map +1 -0
  197. package/lib/variants.js +82 -0
  198. package/lib/variants.js.map +1 -0
  199. package/package.json +1 -1
  200. package/rt-tools-agent-kit-0.4.0.tgz +0 -0
  201. package/assets/laws/admin-lists.md +0 -35
  202. package/assets/laws/admin-navigation.md +0 -38
  203. package/rt-tools-agent-kit-0.2.0.tgz +0 -0
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: git-workflow-commit
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow для дерева на GitLab. Брать на заведение задачи, ветки, коммит, пуш и создание MR — заведение задачи со всеми шагами, перевод по спискам доски, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, строка связи с задачей, ревьювер, исполнитель и метки MR, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
6
+ ---
7
+
8
+ # Ветка, коммит и MR
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
11
+ `docs/constitution/delivery.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - Заводится задача, с которой начинается правка.
16
+ - Заводится ветка под задачу.
17
+ - Готовится коммит или пуш.
18
+ - Открывается MR.
19
+ - Работа перешла на следующий шаг, и задача переставляется в другой список доски.
20
+
21
+ ## Сначала задача на доске, потом ветка
22
+
23
+ Заведение состоит из четырёх шагов: issue, номер в его заголовке, исполнитель, метка первого
24
+ списка доски. Доска показывает те issue, чью метку знает, — поэтому четвёртый шаг сам не
25
+ случается, и задача без него заведена, но в очереди работ её нет.
26
+
27
+ Все четыре делает одна команда дерева, а не рука: делить их значит забывать последний.
28
+
29
+ ```bash
30
+ npm run task:new -- --title 'Письма владельцу не уходят молча' \
31
+ --label bug --label area:api --slug mail-owner-silence < описание.md
32
+ ```
33
+
34
+ Тело читается со стандартного ввода, `--slug` необязателен и идёт только в подсказку с именем
35
+ ветки. Автор и исполнитель — учётная запись машинной работы; токен команда читает сама, из
36
+ файла вне репозитория.
37
+
38
+ Скрипт под этой командой заводит проект — пакет её не везёт. Что он делает вызовами `glab`:
39
+
40
+ ```bash
41
+ glab issue create --title '[<КЛЮЧ>-<номер>] …' --label bug --label 'status::backlog' \
42
+ --assignee <бот> --description-file -
43
+ glab issue update <номер> --title '[<КЛЮЧ>-<номер>] …' # номер известен только после создания
44
+ ```
45
+
46
+ Метка списка ставится при заведении, а не после: issue без неё лежит вне доски, и увидеть её
47
+ можно только поиском по проекту.
48
+
49
+ Чем сверить, что очередь работ в порядке:
50
+
51
+ ```bash
52
+ npm run check:board
53
+ ```
54
+
55
+ Она смотрит только открытое: метку списка, номер и исполнителя у каждой открытой задачи, а у
56
+ каждого открытого MR — номер в заголовке, строку `Closes`, открытую задачу за ним и то, что
57
+ второго MR с тем же номером нет. Имя ветки не судит: у открытого MR его не переименовать.
58
+
59
+ ## Две задачи, которые чинятся одной правкой
60
+
61
+ Если по ходу выяснилось, что правка закрывает и соседнюю задачу, — это одна задача, а не две.
62
+ Слить их можно, пока правка не въехала в главную ветку:
63
+
64
+ ```bash
65
+ # то, чего в поглотившей задаче не было, дописывается в её описание
66
+ glab issue update <поглотившая> --description "$(cat тело.md)"
67
+ # поглощённая закрывается как дубликат, со ссылкой на поглотившую
68
+ glab issue note <поглощённая> --message 'Дубликат #<поглотившая>: чинится той же правкой.'
69
+ glab issue close <поглощённая>
70
+ ```
71
+
72
+ Закрытая как дубликат уходит из очереди работ, а её номер остаётся в истории — этим GitLab
73
+ отличается от хостингов, где задачу можно стереть. Ссылка на поглотившую обязательна: без неё
74
+ закрытая задача читается как сделанная, а сделана она не была.
75
+
76
+ После слияния ветки поглощения нет: она въехала, и откатывается целиком.
77
+
78
+ ## Ветка заводится отдельным вызовом
79
+
80
+ Гард главной ветки разбирает текст команды и смотрит ветку на момент запуска, поэтому
81
+ составная команда отклоняется целиком — ветки в ней ещё нет:
82
+
83
+ ```bash
84
+ ✗ git checkout -b <КЛЮЧ>-85-guest-token && git commit -m 'feat(admin): …'
85
+ ✓ git checkout -b <КЛЮЧ>-85-guest-token
86
+ ✓ git commit -F -
87
+ ```
88
+
89
+ Имя — `<КЛЮЧ>-<номер задачи>-<короткий-slug>`, slug строчными латинскими через дефис. Гард
90
+ поставки разбирает его на месте и отбивает промах в форме до первого коммита, а по номеру
91
+ спрашивает доску: задача должна существовать, быть открытой, стоять в очереди и иметь
92
+ исполнителя.
93
+
94
+ Имя без номера (`feat/…`, `fix/…`) законно, пока ветка живёт локально — под пробу и разбор.
95
+ MR с неё не откроется: правка, доезжающая до главной ветки, начинается с задачи.
96
+
97
+ ## Список задачи двигается вместе с работой
98
+
99
+ Ветка заведена — задача уже не в первом списке, а в работе. MR открыт — она ждёт разбора.
100
+ Оба перевода делает одна команда, вторым вызовом сразу за тем, который его вызвал:
101
+
102
+ ```bash
103
+ npm run task:move -- 86 in-progress # сразу после git checkout -b <КЛЮЧ>-86-…
104
+ npm run task:move -- 86 in-review # сразу после glab mr create
105
+ ```
106
+
107
+ Списки доски — это метки, поэтому перевод обязан снять прежнюю:
108
+
109
+ ```bash
110
+ glab issue update 86 --label 'status::in-progress' --unlabel 'status::backlog'
111
+ ```
112
+
113
+ Перевод, не снявший прежнюю метку, оставляет задачу в двух списках сразу, и очередь читается
114
+ неверно — в обоих местах она выглядит настоящей.
115
+
116
+ Перевод не откладывается на потом: очередь работ читают между шагами, а не после них.
117
+
118
+ ## Коммит подписывается учётной записью машинной работы
119
+
120
+ Токен читается в переменную и не печатается; автор и коммиттер задаются переменными той же
121
+ команды. `git config` не годится — конфиг общий с основным деревом и переписал бы подпись
122
+ владельцу:
123
+
124
+ ```bash
125
+ TOKEN=$(tr -d '\n' < ~/.config/<дерево>-bot-token)
126
+
127
+ GIT_AUTHOR_NAME="<бот>" GIT_AUTHOR_EMAIL="<почта бота>" \
128
+ GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<почта бота>" \
129
+ git commit -F -
130
+ ```
131
+
132
+ Заголовок — `type(scope): description`. Типы: `feat`, `fix`, `refactor`, `docs`, `style`,
133
+ `test`, `chore`, `perf`. Области — свои у дерева, они перечислены в `implementation.md`. Точка
134
+ в конце заголовка не принимается.
135
+
136
+ ```
137
+ feat(site): availability calendar with season prices
138
+ fix(api): reject overlapping booking dates
139
+ chore(deploy): docker-compose for vps
140
+ ```
141
+
142
+ ## Документ едет тем же коммитом
143
+
144
+ `docs-guard` требует пару и называет её сам. Обход — строка в теле, причина обязательна:
145
+
146
+ ```
147
+ Docs-skip: правка только в тестах хука, зеркала у него нет
148
+ ```
149
+
150
+ ## Номер задачи стоит в её заголовке и в заголовке MR
151
+
152
+ Форма одна на оба — `[<КЛЮЧ>-<номер>] <текст>`. Номер стоит в самом заголовке, а не только в
153
+ теле: в списке MR тела не видно, а в списке задач номер иначе приходится искать глазами. Тот же
154
+ номер несёт и имя ветки, поэтому задача, ветка и MR читаются как одно.
155
+
156
+ Задача говорит, что не так; MR тем же номером отчитывается, что сделано:
157
+
158
+ ```
159
+ задача [<КЛЮЧ>-86] Пустой адрес владельца — письма не уходят молча
160
+ MR [<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи
161
+ ```
162
+
163
+ Инфинитив из задачи в заголовок MR не переносится: «исправить» становится «исправлено»,
164
+ «вернуть» — «возвращено», «добавить» — «добавлено».
165
+
166
+ Тип и область — `fix(site):`, `docs(common):` — в заголовок MR не идут: это формат заголовка
167
+ коммита, и там его сверяет `commitlint`. В списке MR он занимает место, ничего не добавляя:
168
+ род правки и область уже видны метками.
169
+
170
+ ## MR прикрепляется к задаче
171
+
172
+ Описание начинается со строки связи. Ревьювер, исполнитель и метки задаются той же командой, и
173
+ MR без них не открывается:
174
+
175
+ ```bash
176
+ GITLAB_TOKEN="$TOKEN" glab mr create \
177
+ --title '[<КЛЮЧ>-86] Письмо владельцу с незаполненным адресом попадает в логи' \
178
+ --assignee <бот> --reviewer <владелец> --label bug --label area:api \
179
+ --target-branch main --remove-source-branch \
180
+ --description 'Closes #86
181
+
182
+ …'
183
+ ```
184
+
185
+ Ревьювер — всегда владелец: без запроса разбора MR не показывается ему в очереди. Исполнитель —
186
+ та же учётная запись, от которой идёт машинная работа. Метки читаются у задачи, а не выбираются
187
+ по памяти:
188
+
189
+ ```bash
190
+ glab issue view 86 --output json | jq -r '[.labels[]] | join(",")'
191
+ ```
192
+
193
+ Строка `Closes #<номер>` обязательна: без неё MR не прикрепляется к задаче, и сверка очереди
194
+ это находит. Она же означает, что задача закрывается целиком — половину задачи одним MR не
195
+ выкатывают: у задачи одна ветка, и работа, которая в неё не влезает, делится на задачи до того,
196
+ как ветка заводится.
197
+
198
+ У уже открытого MR то же ставится правкой:
199
+
200
+ ```bash
201
+ glab mr update 205 --label bug --label area:api --assignee <бот> --reviewer <владелец>
202
+ glab mr update 205 --description "$(cat тело.md)"
203
+ ```
204
+
205
+ Правка описания переписывает его целиком, поэтому строка `Closes #<номер>` пишется заново
206
+ вместе с остальным текстом. Тело перечитывается всякий раз, когда в ветку что-то влилось после
207
+ публикации: отчёт утверждает про дерево, а дерево с тех пор изменилось.
208
+
209
+ ## Состояние MR читается, а не додумывается
210
+
211
+ Команды правки отвечают нулевым кодом и тогда, когда ничего не сделали: токен без права на
212
+ проект молча не ставит ни метку, ни ревьювера. Поэтому после них MR перечитывают:
213
+
214
+ ```bash
215
+ glab mr view 205 --output json \
216
+ | jq '{author: .author.username, reviewers: [.reviewers[].username], labels: .labels}'
217
+ ```
218
+
219
+ Владельцу называют то, что прочитали, а не то, что заказывали.
220
+
221
+ Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
222
+ MR выбираются отдельно, и токен для публикации — всегда токен машинной работы.
223
+
224
+ Открытый MR означает, что задача ждёт разбора, — список переставляется тем же движением:
225
+
226
+ ```bash
227
+ npm run task:move -- 86 in-review
228
+ ```
229
+
230
+ ## Что проверяется до публикации MR
231
+
232
+ Проверок на самом MR нет ровно до тех пор, пока конвейер не запущен, а запускается он пушем.
233
+ Линтеры, юниты и сценарии хуков снимает гейт пуша — ниже то, чего он не знает.
234
+
235
+ 1. **В ветке только та правка, за которой её заводили** — `git diff main...HEAD --stat`. Чужой
236
+ домен в списке файлов означает, что правка расползлась, и её надо вернуть в свои границы.
237
+ 2. **Ни мока, ни подменённого ответа, ни отладочной строки** — `git diff main...HEAD` читается
238
+ целиком, а не по именам файлов. На прод они уезжают молча и портят настоящие данные.
239
+ 3. **Документ едет тем же коммитом.** Пару называет `docs-guard`, но спек домена и правку его
240
+ поведения он не знает — это остаётся за автором.
241
+ 4. **Проверки текстов и раскладки зелёные** — те, что дерево завело в `tools/`. Какие именно
242
+ есть здесь — `implementation.md` правила.
243
+ 5. **Все приложения дерева собираются** — `nx build` по каждому. Гейт пуша сборку не гоняет.
244
+ 6. **Видимый текст заведён во всех локалях перевода** — тестом полноты словарей, если дерево
245
+ переводится.
246
+ 7. **Правка вёрстки подтверждена замером**, а не взглядом, и снята при узком экране — паттерн
247
+ `browser-verification-measure`.
248
+ 8. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** —
249
+ паттерн `seo-verify`.
250
+ 9. **Описание MR начинается строкой `Closes #<номер>`**, а метки, ревьювер и исполнитель стоят.
251
+ 10. **Заголовок MR несёт номер задачи и называет её сделанной:** `[<КЛЮЧ>-<номер>] <Что
252
+ сделано>`, тем же номером, что стоит у задачи и в имени ветки.
253
+ 11. **Очередь работ сходится** — `npm run check:board`.
254
+ 12. **Состояние MR прочитано, а не выведено из кодов возврата.**
255
+
256
+ Сразу после публикации задача переставляется в разбор, и сверка очереди прогоняется ещё раз: до
257
+ открытия MR список она не судит, а после открытия расхождение видит.
258
+
259
+ Сделанное рассуждением и сделанное замером в теле MR разводятся прямо: непроверенное,
260
+ названное проверенным, ревьювер принимает за проверенное.
261
+
262
+ ## Частые промахи
263
+
264
+ - Метка списка не поставлена при заведении: задача есть, а на доске её нет. Доска показывает
265
+ только то, чью метку знает.
266
+ - Перевод по списку не снял прежнюю метку: задача стоит в двух списках сразу.
267
+ - `glab` не видит проект: у токена область `read_api` вместо `api`. Команды правки при этом
268
+ отвечают успехом и не делают ничего.
269
+ - `git add` с несколькими путями не добавляет ничего, если хоть один путь не существует:
270
+ команда обрывается на первом промахе целиком. Следующий `git commit --amend` при этом уносит
271
+ в коммит всё, что осталось в индексе. Состав коммита читается `git show --stat` сразу после
272
+ него, а не на разборе MR.
273
+ - MR открыт без ревьювера: он не попадает во входящие владельца, и очередь стоит, выглядя
274
+ работающей.
275
+ - Метки поставлены по названию MR, а не прочитаны у задачи: область теряется, и по доске не
276
+ видно, что правка задела ещё и соседний домен.
277
+ - Вторая строка `Closes` в одном MR: две задачи в одной ветке откатываются только вместе. Либо
278
+ это одна задача — и вторая поглощается, — либо две ветки.
279
+ - Половина задачи, уехавшая своим MR: описание такого MR начинается со слов «Часть #<номер>»
280
+ вместо `Closes`, задача остаётся открытой, и после отката видно её целой.
281
+ - `--remove-source-branch` забыт: ветки задач копятся в репозитории, и по списку веток больше
282
+ не видно, какая работа идёт сейчас.
283
+ - Правка владельца ни токена, ни переменных не берёт — они только для машинной работы.
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: git-workflow-merge
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать, когда главная ветка вливается в ветку задачи и разрешается конфликт — порядок мержа, разбор конфликта по роду файла, сверка дописанного веткой с очередью работ, проверки после разрешения, перечитывание тела уже открытого PR. Не брать для заведения ветки, коммита и PR — это паттерн git-workflow-commit.
6
+ ---
7
+
8
+ # Мерж главной ветки в ветку задачи
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
11
+ `docs/constitution/delivery.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - PR отмечен конфликтующим, и его надо вернуть к сливаемому состоянию.
16
+ - Главная ветка ушла вперёд, и ветку задачи надо подтянуть до проверок.
17
+ - Коммит переносится черри-пиком.
18
+
19
+ ## Порядок
20
+
21
+ ```bash
22
+ git fetch origin
23
+ git merge origin/main --no-edit
24
+ git diff --name-only --diff-filter=U # что встало конфликтом
25
+ ```
26
+
27
+ Список конфликтов читается целиком до первого разрешения: род файла решает приём, и разные
28
+ файлы одного мержа разрешаются по-разному.
29
+
30
+ | Что встало конфликтом | Как разрешается |
31
+ | -------------------------------- | ---------------------------------------------------------------------------------- |
32
+ | код | ловушка правила `git-workflow` про сторону-удаление; после — `npm run check:dupes` |
33
+ | спек в `docs/specs/` | сохранением обеих сторон — правило `spec-driven`; после — `npm run check:specs` |
34
+ | список работ (`docs/BACKLOG.md`) | признаком отбора — паттерн `doc-style-sweep` |
35
+
36
+ ## Что дописала ветка, видно только от точки расхождения
37
+
38
+ Конфликтный маркер показывает место, а не правку: сторона ветки в нём — её допись вместе со
39
+ всем, что лежало в файле до неё.
40
+
41
+ ```bash
42
+ git diff "$(git merge-base origin/main HEAD)" HEAD -- docs/BACKLOG.md
43
+ ```
44
+
45
+ ## Дописанное веткой сверяется с очередью работ, а не переносится по умолчанию
46
+
47
+ Раздел, который ветка дописала в список работ, к моменту мержа обычно уже стоит задачей:
48
+ ветка живёт неделями, а замеченный по ходу дефект заводится задачей сразу. Перенести его
49
+ второй раз — завести вторую запись об одной работе.
50
+
51
+ ```bash
52
+ /opt/homebrew/bin/gh issue list --state all --limit 400 --search '<слова из раздела>' \
53
+ --json number,title,state
54
+ ```
55
+
56
+ Задача несёт то же содержание — сторона ветки не переносится:
57
+
58
+ ```bash
59
+ git checkout --theirs docs/BACKLOG.md && git add docs/BACKLOG.md
60
+ ```
61
+
62
+ В мерже `--theirs` — влитая главная ветка, а `--ours` — ветка задачи; при перебазировании
63
+ стороны меняются местами. Взятая не та сторона стирает работу молча.
64
+
65
+ ## Проверки после разрешения
66
+
67
+ Конфликт в текстах кода не задевает, и зелёная сборка про него ничего не говорит:
68
+
69
+ ```bash
70
+ grep -rn '^<<<<<<< \|^>>>>>>> ' --exclude-dir=node_modules --exclude-dir=.git .
71
+ npm run check:docs && npm run check:specs && npm run check:dupes && npm run check:board
72
+ bash .claude/hooks/tests/run.sh # если конфликт задел хуки
73
+ ```
74
+
75
+ Коммит мержа подписывается ботом тем же способом, что и любой другой, — паттерн
76
+ `git-workflow-commit`. После пуша состояние читается у самого PR, а не по своему дереву:
77
+
78
+ ```bash
79
+ /opt/homebrew/bin/gh pr view <номер> --json mergeable,mergeStateStatus
80
+ ```
81
+
82
+ ## Тело открытого PR перечитывается после мержа
83
+
84
+ Отчёт описывал дерево на день, когда его написали. Мерж главной ветки меняет то, о чём он
85
+ утверждает: тело говорило, что оба дефекта заведены в `docs/BACKLOG.md`, а главная ветка этот
86
+ список к тому времени разобрала. Правится тело вызовом REST — `gh pr edit` в этом репозитории
87
+ отвечает отказом про Projects (classic) и до правки не доходит:
88
+
89
+ ```bash
90
+ /opt/homebrew/bin/gh api -X PATCH repos/<владелец>/<репозиторий>/pulls/<номер> -f body="$(cat тело.md)"
91
+ ```
92
+
93
+ ## Частые промахи
94
+
95
+ - «Сохранить обе стороны» применено ко всем файлам одинаково: в спеке это верно, в коде и в
96
+ списке работ — нет.
97
+ - Сторона ветки перенесена без сверки с очередью работ: одна работа стала двумя записями.
98
+ - После разрешения прогнана сборка, а проверки текстов — нет: конфликта в них сборке не видно.
99
+ - Тело PR оставлено прежним: ревьювер читает утверждение о дереве, которого больше нет.
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: git-workflow-migration
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать при правке prisma/schema.prisma и prisma/migrations/** — готовые команды одноразового контейнера, написание файла миграции через migrate diff, накат локальной базы. Не брать для коммита и PR — это паттерн git-workflow-commit.
6
+ ---
7
+
8
+ # Миграция и прогон цепочки
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
11
+ `docs/constitution/delivery.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - Правится `prisma/schema.prisma`.
16
+ - Заводится или переименовывается каталог в `prisma/migrations/`.
17
+ - Ветка с новой миграцией готовится к мержу.
18
+
19
+ ## Цепочка гоняется одной командой
20
+
21
+ Локальные `lint`, `test`, `check:all` и сборки порядок миграций не трогают вовсе, а шаг
22
+ `Migrations match schema` в `.github/workflows/deploy.yml` идёт уже после мержа. Проверка
23
+ стоит гейтом пуша и зовётся руками:
24
+
25
+ ```bash
26
+ npm run check:schema
27
+ ```
28
+
29
+ Она накатывает цепочку на теневую базу — ту же, что рабочая, с суффиксом `_gate_shadow`, —
30
+ сравнивает её со схемой и сносит. Своя база при этом не трогается: сверка с ней судила бы о
31
+ состоянии машины, а не репозитория. Погашенный докер и боевой адрес проверка пропускает
32
+ молча.
33
+
34
+ Когда базы под рукой нет вовсе, та же цепочка гоняется на одноразовом контейнере:
35
+
36
+ ```bash
37
+ docker run -d --rm --name <префикс>-migcheck -e POSTGRES_PASSWORD=migcheck -p 55432:5432 postgres:16-alpine
38
+ docker exec <префикс>-migcheck pg_isready -U postgres # накат до готовности падает на соединении
39
+ DATABASE_URL=postgresql://postgres:migcheck@localhost:55432/postgres npx prisma migrate deploy
40
+ DATABASE_URL=postgresql://postgres:migcheck@localhost:55432/postgres npx prisma migrate diff \
41
+ --from-config-datasource --to-schema prisma/schema.prisma --exit-code
42
+ docker stop <префикс>-migcheck
43
+ ```
44
+
45
+ Адрес ставится префиксом самой команды — `export` между вызовами не живёт.
46
+
47
+ ## Файл миграции пишется тем же контейнером
48
+
49
+ `prisma migrate dev` не запускается ни командой, ни через `npm run prisma:migrate`: любое
50
+ расхождение состояния он лечит предложением сбросить базу, а в локальной базе лежат объекты и
51
+ брони владельца. Файл берётся разницей между накатанной цепочкой и схемой:
52
+
53
+ ```bash
54
+ DATABASE_URL=postgresql://postgres:migcheck@localhost:55432/postgres npx prisma migrate diff \
55
+ --from-config-datasource --to-schema prisma/schema.prisma --script \
56
+ > prisma/migrations/<метка>_<имя>/migration.sql
57
+ ```
58
+
59
+ Каталог заводится **после** наката цепочки: пустой каталог, попавший в `migrate deploy`,
60
+ помечается применённым, и его содержимое на этот контейнер уже не встанет.
61
+
62
+ ## Локальная база догоняет ветку
63
+
64
+ ```bash
65
+ npx prisma migrate deploy
66
+ ```
67
+
68
+ Переименованная миграция остаётся в ней под прежним именем, и накат падает на
69
+ `relation … already exists`. Состояние правится, повторный накат его не чинит:
70
+
71
+ ```bash
72
+ npx prisma migrate resolve --applied <новое имя>
73
+ ```
74
+
75
+ ## Частые промахи
76
+
77
+ - Метку времени ставит момент создания, а порядок применения лексикографический: миграция из
78
+ ветки, начатой раньше, встаёт перед той, от которой зависит. На существующей базе это
79
+ незаметно — падает только накат с нуля.
80
+ - Флаги `prisma migrate diff` не те, что в примерах из сети: `--from-url`, `--to-url`,
81
+ `--shadow-database-url` и `--to-schema-datamodel` сняты, а `prisma db execute` адреса
82
+ базы не принимает вовсе и берёт его из `prisma.config.ts`. На неизвестный флаг обе команды
83
+ печатают справку, и промах виден только в ней. Какие флаги есть сейчас, смотрят в
84
+ `prisma migrate diff --help`, а не в этом тексте.
85
+ - Запись в боевую базу (порт 15432, прод-хост) запрещена совсем: схема меняется миграцией
86
+ через деплой, данные — через админку.
87
+ - Строки адресуются по первичному ключу, а не по маске: удаление по маске почты однажды унесло
88
+ вместе с тестовыми записями демонстрационные брони владельца.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: git-workflow-restart
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать при ручном перезапуске прода — после правки .env.prod, при разборе выкатки, при подъёме контейнера на сервере. Готовые команды с IMAGE_TAG по sha, способ узнать выкаченный sha и чем сверять результат. Не брать для коммита и миграций — это паттерны git-workflow-commit и git-workflow-migration.
6
+ ---
7
+
8
+ # Ручной перезапуск прода
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон
11
+ `docs/constitution/delivery.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - Правился `.env.prod` и контейнер надо поднять заново.
16
+ - Разбирается, что именно сейчас выкачено.
17
+ - Контейнер поднимается на сервере руками, мимо выкатки по мержу.
18
+
19
+ ## Команда обязана нести sha
20
+
21
+ `.github/workflows/deploy.yml` выкатывает образы по sha коммита. Без переменной `docker
22
+ compose` подставляет умолчание `latest`, а `latest` в реестре отстаёт от главной ветки — прод
23
+ молча откатывается на старый образ и при этом отвечает:
24
+
25
+ ```bash
26
+ IMAGE_TAG='<sha>' docker compose -f docker-compose.prod.yml --env-file .env.prod pull migrate api ssr web
27
+ IMAGE_TAG='<sha>' docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-build --remove-orphans
28
+ ```
29
+
30
+ ## Sha берётся до перезапуска
31
+
32
+ У выкаченного контейнера или у последнего мержа в главную ветку:
33
+
34
+ ```bash
35
+ docker inspect <контейнер> --format '{{.Config.Image}}'
36
+ ```
37
+
38
+ ## Сверка идёт по логу, а не по коду ответа
39
+
40
+ Подмена образа видна только по пропавшим строкам нового кода: сводка `startup` с
41
+ `integrations` из логов исчезает, хотя `API is running` остаётся на месте. После перезапуска —
42
+ тот же `inspect` и наличие ожидаемых строк в логе.
43
+
44
+ ## Частые промахи
45
+
46
+ - Вывод «прод жив, значит выкатилось» — код ответа подмену образа не показывает.
47
+ - Переменные окружения, секреты и записи имён ставятся **до** мержа: мерж выкатывает сразу,
48
+ и ветка, зависящая от новой переменной, встаёт на проде до того, как переменную заведут.
49
+ - Заход на сервер по ssh в автоматическом режиме режется правилом — нужен обычный режим.
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: lib-layers-move
3
+ kind: pattern
4
+ rule: lib-layers
5
+ description: Паттерн правила lib-layers. Брать при переносе кода или символа между либами — с чего начинать, в каком порядке двигать домены, что делать с границами, импортами и README обеих либ, и чем проверять. Заведение и удаление самой либы — паттерн lib-layers-new.
6
+ ---
7
+
8
+ # Перенести код между либами
9
+
10
+ Паттерн правила `lib-layers`. Что при этом должно быть верно — закон
11
+ `docs/constitution/lib-imports.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - Символ переезжает из одной либы в другую.
16
+ - Домен переносится в новую раскладку.
17
+ - Общий код собирается из копий в одно место.
18
+
19
+ ## Начинать с `docs/plans/`
20
+
21
+ ```bash
22
+ grep -rn "<имя либы>" docs/
23
+ ```
24
+
25
+ Решение о том, куда переезжает код, часто уже принято и записано, а принятое заново с ним
26
+ расходится. Перенос утилит списка из-за этого делался дважды: первая редакция положила их в
27
+ `libs/common/util`, что запрещено первым же пунктом того самого плана, и её пришлось
28
+ откатывать целиком.
29
+
30
+ ## Порядок задаёт граф зависимостей, а не список в плане
31
+
32
+ Домен переносится после всех, от кого он зависит. Списки доменов в планах отсортированы по
33
+ важности, и следование им в лоб заставляет временно расширять границы.
34
+
35
+ ```bash
36
+ grep -rn "@<область>/<семья>/<домен>" libs/ apps/ | sed 's/:.*//' | sort -u
37
+ ```
38
+
39
+ Рёбра выписываются грепом по алиасам домена и сортируются топологически. Каждая временная
40
+ строка в границах — это ослабленная механическая проверка, ради которой нарезка и затевалась.
41
+
42
+ ## Куда именно кладётся общее
43
+
44
+ Своя либа заводится тогда, когда ни одна существующая код не видит.
45
+
46
+ | Кому нужно | Куда |
47
+ | -------------------------------------- | ----------------------------------------------------------- |
48
+ | бэкенду или обоим фронтам, без Angular | `libs/common/util` |
49
+ | только фронтам, тянет Angular | `common/platform` — сервис и токен, `common/ui` — компонент |
50
+ | предмету, у которого уже есть либа | в неё: `site-routing`, `i18n`, `photo`, `captcha` |
51
+ | всем доменам одной семьи | основание семейства `<семья>/core` |
52
+ | всему бэкенду | тот слой `util`, что уже перечислен у каждого домена |
53
+
54
+ Новых строк в границах при таком переезде не появляется — кроме права видеть контракт, если
55
+ код его читает.
56
+
57
+ ## После переезда
58
+
59
+ 1. **README обеих либ.** У той, откуда файл ушёл, и у той, куда пришёл: README перечисляет, что
60
+ в либе лежит и кто её зовёт. Ни одна проверка эти тексты не читает.
61
+ 2. **Порядок импортов.** Переезд алиаса его ломает, и приходит это ошибкой `prettier/prettier`
62
+ из линта, а не из сборки:
63
+
64
+ ```bash
65
+ npx nx lint <project> --fix
66
+ ```
67
+
68
+ Флага `--fix` нет у `test` и `build`, поэтому в `run-many -t lint test` его передавать
69
+ нельзя — падает весь вызов.
70
+
71
+ 3. **Линт по всем затронутым проектам, а не по одному приложению.** Скрипт ошибается молча и не
72
+ так, как человек: строка импорта не переписывается, а исчезает целиком. При переносе утилит
73
+ списка так пропали импорты в шести файлах из восьми, и нашёл их прогон по списку проектов —
74
+ сборка одного приложения до этих файлов не дошла.
75
+
76
+ ```bash
77
+ npx nx run-many -t lint --projects=<список по изменённым файлам>
78
+ ```
79
+
80
+ ## Проверить
81
+
82
+ ```bash
83
+ npm run check:layers
84
+ npm run check:dupes
85
+ ```
86
+
87
+ Второе обязательно: перенос и есть тот момент, когда копия остаётся на старом месте.
88
+
89
+ ## Частые промахи
90
+
91
+ - Новый адрес выбран без чтения `docs/plans/` — расходится с уже принятым решением.
92
+ - Порядок переноса взят из списка в плане — приходится временно расширять границы.
93
+ - README поправлен только у одной либы.
94
+ - Линт прогнан по приложению, а не по списку затронутых проектов — пропавшие импорты не видно.
95
+ - Копия осталась на старом месте, а `check:dupes` не гонялся.