@rt-tools/agent-kit 0.1.0 → 0.3.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 (131) hide show
  1. package/README.md +88 -9
  2. package/assets/hooks/browser-device-id.sh +20 -0
  3. package/assets/hooks/browser-guard-device-id.sh +27 -0
  4. package/assets/hooks/browser-guard-no-listing.sh +17 -0
  5. package/assets/hooks/browser-guard-no-other-drivers.sh +78 -0
  6. package/assets/hooks/browser-guard-require-select.sh +53 -0
  7. package/assets/hooks/commit-msg.sh +26 -0
  8. package/assets/hooks/constitution-index.sh +42 -0
  9. package/assets/hooks/dev-server-guard.sh +113 -0
  10. package/assets/hooks/docs-guard.sh +96 -0
  11. package/assets/hooks/git-guard-delivery.sh +110 -0
  12. package/assets/hooks/git-guard-main.sh +72 -0
  13. package/assets/hooks/git-guard-push-tests.sh +73 -0
  14. package/assets/hooks/lint-after-edit.sh +94 -0
  15. package/assets/hooks/qa-dataid-guard.sh +81 -0
  16. package/assets/hooks/reuse-first-guard.sh +83 -0
  17. package/assets/hooks/skill-gate-rearm.sh +22 -0
  18. package/assets/hooks/skill-gate.sh +68 -0
  19. package/assets/hooks/skill-loaded.sh +20 -0
  20. package/assets/hooks/sql-guard.sh +129 -0
  21. package/assets/laws/access.md +3 -12
  22. package/assets/laws/admin-lists.md +9 -21
  23. package/assets/laws/admin-navigation.md +3 -15
  24. package/assets/laws/code-structure.md +5 -16
  25. package/assets/laws/delivery.md +2 -16
  26. package/assets/laws/entity-editing.md +7 -20
  27. package/assets/laws/entity-models.md +10 -17
  28. package/assets/laws/frontend-application.md +3 -14
  29. package/assets/laws/lib-imports.md +0 -13
  30. package/assets/laws/locales.md +2 -11
  31. package/assets/laws/project-documentation.md +7 -20
  32. package/assets/laws/reuse-first.md +0 -9
  33. package/assets/laws/search-visibility.md +0 -13
  34. package/assets/laws/shared-code.md +0 -13
  35. package/assets/laws/verifiability.md +0 -13
  36. package/assets/patterns/angular-patterns-state.md +94 -0
  37. package/assets/patterns/api-layer-pair.md +78 -0
  38. package/assets/patterns/browser-verification-measure.md +83 -0
  39. package/assets/patterns/browser-verification-stand.md +79 -0
  40. package/assets/patterns/component-structure-new.md +98 -0
  41. package/assets/patterns/doc-style-sweep.md +100 -0
  42. package/assets/patterns/doc-style-write.md +106 -0
  43. package/assets/patterns/git-workflow-commit.md +175 -0
  44. package/assets/patterns/git-workflow-merge.md +82 -0
  45. package/assets/patterns/git-workflow-migration.md +58 -0
  46. package/assets/patterns/git-workflow-restart.md +49 -0
  47. package/assets/patterns/lib-layers-move.md +77 -0
  48. package/assets/patterns/lib-layers-new.md +70 -0
  49. package/assets/patterns/permissions-procedure.md +69 -0
  50. package/assets/patterns/platform-access-di.md +70 -0
  51. package/assets/patterns/reuse-first-extend.md +73 -0
  52. package/assets/patterns/seo-page.md +92 -0
  53. package/assets/patterns/seo-verify.md +64 -0
  54. package/assets/patterns/shared-code-new.md +80 -0
  55. package/assets/patterns/spec-driven-domain.md +100 -0
  56. package/assets/patterns/spec-driven-rule.md +112 -0
  57. package/assets/patterns/styling-bem-component.md +77 -0
  58. package/assets/patterns/styling-bem-layout.md +67 -0
  59. package/assets/patterns/testing-e2e.md +90 -0
  60. package/assets/patterns/testing-unit.md +93 -0
  61. package/assets/patterns/translations-key.md +51 -0
  62. package/assets/patterns/ts-procedure.md +66 -0
  63. package/assets/rules/angular-patterns.md +52 -0
  64. package/assets/rules/api-layer.md +53 -0
  65. package/assets/rules/browser-verification.md +69 -0
  66. package/assets/rules/component-structure.md +48 -0
  67. package/assets/rules/doc-style.md +61 -0
  68. package/assets/rules/git-workflow.md +106 -0
  69. package/assets/rules/lib-layers.md +54 -0
  70. package/assets/rules/permissions.md +52 -0
  71. package/assets/rules/platform-access.md +49 -0
  72. package/assets/rules/reuse-first.md +69 -0
  73. package/assets/rules/seo.md +50 -0
  74. package/assets/rules/shared-code.md +45 -0
  75. package/assets/rules/spec-driven.md +89 -0
  76. package/assets/rules/styling-bem.md +59 -0
  77. package/assets/rules/testing.md +69 -0
  78. package/assets/rules/translations.md +52 -0
  79. package/assets/rules/typescript-conventions.md +46 -0
  80. package/assets/templates/gate-map.sh +37 -0
  81. package/assets/templates/implementation.md +38 -0
  82. package/assets/templates/pattern.md +4 -0
  83. package/assets/templates/project.sh +41 -0
  84. package/assets/templates/rule.md +12 -23
  85. package/bin/agent-kit.d.ts +1 -1
  86. package/bin/agent-kit.d.ts.map +1 -1
  87. package/bin/agent-kit.js +63 -7
  88. package/bin/agent-kit.js.map +1 -1
  89. package/bin/prompt.d.ts +9 -0
  90. package/bin/prompt.d.ts.map +1 -0
  91. package/bin/prompt.js +57 -0
  92. package/bin/prompt.js.map +1 -0
  93. package/index.d.ts +2 -0
  94. package/index.d.ts.map +1 -1
  95. package/index.js +2 -0
  96. package/index.js.map +1 -1
  97. package/lib/assets.d.ts +10 -2
  98. package/lib/assets.d.ts.map +1 -1
  99. package/lib/assets.js +24 -28
  100. package/lib/assets.js.map +1 -1
  101. package/lib/catalog.d.ts +44 -0
  102. package/lib/catalog.d.ts.map +1 -0
  103. package/lib/catalog.js +86 -0
  104. package/lib/catalog.js.map +1 -0
  105. package/lib/commands.d.ts +13 -1
  106. package/lib/commands.d.ts.map +1 -1
  107. package/lib/commands.js +106 -11
  108. package/lib/commands.js.map +1 -1
  109. package/lib/companion.d.ts +53 -0
  110. package/lib/companion.d.ts.map +1 -0
  111. package/lib/companion.js +33 -0
  112. package/lib/companion.js.map +1 -0
  113. package/lib/config.d.ts +29 -1
  114. package/lib/config.d.ts.map +1 -1
  115. package/lib/config.js +43 -6
  116. package/lib/config.js.map +1 -1
  117. package/lib/picker.d.ts +47 -0
  118. package/lib/picker.d.ts.map +1 -0
  119. package/lib/picker.js +112 -0
  120. package/lib/picker.js.map +1 -0
  121. package/lib/stamp.d.ts +2 -5
  122. package/lib/stamp.d.ts.map +1 -1
  123. package/lib/stamp.js +25 -10
  124. package/lib/stamp.js.map +1 -1
  125. package/lib/sync.d.ts +3 -0
  126. package/lib/sync.d.ts.map +1 -1
  127. package/lib/sync.js +20 -1
  128. package/lib/sync.js.map +1 -1
  129. package/package.json +1 -1
  130. package/rt-tools-agent-kit-0.3.0.tgz +0 -0
  131. package/rt-tools-agent-kit-0.1.0.tgz +0 -0
@@ -0,0 +1,175 @@
1
+ ---
2
+ name: git-workflow-commit
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать на заведение задачи, ветки, коммит, пуш и создание PR — план до первой задачи, заведение задачи всеми шагами сразу, перевод по колонкам, слияние двух задач в одну, работа от учётной записи машинной работы, формат заголовка, строка связи с задачей, состав PR, чеклист проверок до публикации. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
6
+ ---
7
+
8
+ # Ветка, коммит и PR
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон `{{lawsDir}}/delivery.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Заводится задача, с которой начинается правка.
15
+ - Заводится ветка под задачу.
16
+ - Готовится коммит или пуш.
17
+ - Открывается PR.
18
+ - Работа перешла на следующий шаг, и задача переставляется в другую колонку.
19
+
20
+ ## Сначала план, потом задачи
21
+
22
+ Работа, из которой выходит больше одной задачи, начинается с плана, и план показывается
23
+ владельцу до того, как заведена первая задача. Разбивка — решение о том, что делается и в каком
24
+ порядке, и принимает его владелец, а не тот, кто заводит.
25
+
26
+ Заведённые до согласования задачи стоят в очереди как решённое дело: они показывают работу,
27
+ которую никто не заказывал, и убирать их потом дороже, чем не заводить.
28
+
29
+ Признак тот же, что у деления на ветки, — раздельный откат. Один дефект планом не описывается:
30
+ для него сразу заводится задача.
31
+
32
+ Плана нет, а работа делится — сначала пишется план, показывается, и только после ответа
33
+ владельца заводится первая задача. Ответ «делай» — тоже ответ; молчание им не является.
34
+
35
+ ## Сначала задача, потом ветка
36
+
37
+ Заведение состоит из нескольких шагов: сама задача, номер в её заголовке, добавление в очередь,
38
+ начальное состояние. Очередь к репозиторию обычно не привязана, поэтому добавление само не
39
+ случается, и задача без него не видна ни в очереди, ни владельцу. Все шаги делает одна команда
40
+ — не рука.
41
+
42
+ Название задачи говорит, что не так, а не что сделать: PR потом переводит его в сделанное.
43
+ Номер в заголовок руками не пишется — он известен только после создания.
44
+
45
+ ## Две задачи, которые чинятся одной правкой
46
+
47
+ Если по ходу выяснилось, что правка закрывает и соседнюю задачу, — это одна задача, а не две.
48
+ Слить их можно, пока правка не въехала в главную ветку: недостающее из поглощённой дописывается
49
+ в тело первой, и только потом поглощённая закрывается и снимается с очереди. Порядок важен —
50
+ удаление уносит с собой ссылки на неё из чужих тел.
51
+
52
+ После слияния ветки поглощения нет: она въехала, и откатывается целиком.
53
+
54
+ ## Ветка заводится отдельным вызовом
55
+
56
+ Гард главной ветки разбирает текст команды и смотрит ветку на момент запуска, поэтому составная
57
+ команда отклоняется целиком — ветки в ней ещё нет:
58
+
59
+ ```bash
60
+ ✗ git checkout -b <ветка> && git commit -m '…'
61
+ ✓ git checkout -b <ветка>
62
+ ✓ git commit -F -
63
+ ```
64
+
65
+ Имя ветки несёт номер задачи. Гард поставки разбирает его на месте и отбивает промах в форме до
66
+ первого коммита, а по номеру спрашивает очередь: задача должна существовать, быть открытой,
67
+ стоять в очереди и иметь исполнителя.
68
+
69
+ Имя без номера законно, пока ветка живёт локально — под пробу и разбор. PR с неё не откроется:
70
+ правка, доезжающая до главной ветки, начинается с задачи.
71
+
72
+ ## Колонка задачи двигается вместе с работой
73
+
74
+ Ветка заведена — задача уже не в начальной колонке, а в работе. PR открыт — она ждёт разбора.
75
+ Оба перевода делает одна команда, вторым вызовом сразу за тем, который его вызвал.
76
+
77
+ Перевод не откладывается на потом: очередь читают между шагами, а не после них. Задача с
78
+ открытым PR, простоявшая в начальной колонке, всё это время выглядела нетронутой — и разбора за
79
+ неё никто не ждал.
80
+
81
+ ## Коммит подписывается учётной записью машинной работы
82
+
83
+ Токен читается в переменную и не печатается; автор и коммиттер задаются переменными той же
84
+ команды. Правка общей настройки здесь не годится — она переписала бы подпись владельцу:
85
+
86
+ ```bash
87
+ TOKEN=$(tr -d '\n' < <файл с токеном>)
88
+
89
+ GIT_AUTHOR_NAME="<бот>" GIT_AUTHOR_EMAIL="<адрес бота>" \
90
+ GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<адрес бота>" \
91
+ git commit -F -
92
+ ```
93
+
94
+ Заголовок — `тип(область): описание`, без точки в конце. Набор типов и областей задан
95
+ настройкой проверки заголовка.
96
+
97
+ ## Документ едет тем же коммитом
98
+
99
+ Гард документов требует пару и называет её сам. Обход — строка в теле коммита, причина
100
+ обязательна:
101
+
102
+ ```
103
+ Docs-skip: правка только в сценариях хука, зеркала у него нет
104
+ ```
105
+
106
+ ## Номер задачи стоит в её заголовке и в заголовке PR
107
+
108
+ Форма одна на оба. Номер стоит в самом заголовке, а не только в теле: в списке PR тела не
109
+ видно. Тот же номер несёт и имя ветки — поэтому задача, ветка и PR читаются как одно.
110
+
111
+ Задача говорит, что не так; PR тем же номером отчитывается, что сделано. Инфинитив из задачи в
112
+ заголовок PR не переносится: «исправить» становится «исправлено».
113
+
114
+ Тип и область коммита в заголовок PR не идут: род правки и область уже видны метками.
115
+
116
+ ## PR прикрепляется к задаче
117
+
118
+ Тело начинается со строки связи с задачей — по ней в очереди заполняется поле связанных PR.
119
+ Ревьювер, исполнитель и метки задаются той же командой, и PR без них не открывается.
120
+
121
+ Ревьювер — всегда владелец: без запроса разбора PR не показывается ему в очереди. Метки берутся
122
+ у задачи целиком — и род правки, и все её области; читаются они у задачи, а не выбираются по
123
+ памяти.
124
+
125
+ Строка связи обязательна: без неё PR не прикрепляется к задаче. Она же означает, что задача
126
+ закрывается целиком — половину задачи одним PR не выкатывают: у задачи одна ветка, и работа,
127
+ которая в неё не влезает, делится на задачи до того, как ветка заводится.
128
+
129
+ Тело перечитывается всякий раз, когда в ветку что-то влилось после публикации: отчёт утверждает
130
+ про дерево, а дерево с тех пор изменилось.
131
+
132
+ ## Что проверяется до публикации PR
133
+
134
+ Проверок на самом PR нет: выкатка запускается пушем в главную ветку, и до слияния никто не
135
+ гоняет ничего. Линтеры и юниты снимает гейт пуша — ниже то, чего он не знает.
136
+
137
+ 1. **В ветке только та правка, за которой её заводили** — сводка расхождения с главной веткой.
138
+ Чужой домен в списке файлов означает, что правка расползлась.
139
+ 2. **Ни мока, ни подменённого ответа, ни отладочной строки** — расхождение читается целиком, а
140
+ не по именам файлов. На прод они уезжают молча и портят настоящие данные.
141
+ 3. **Документ едет тем же коммитом.** Пару называет гард, но спек домена и правку его поведения
142
+ он не знает — это остаётся за автором.
143
+ 4. **Проверки текстов и раскладки зелёные.**
144
+ 5. **Все приложения собираются.** Гейт пуша сборку обычно не гоняет.
145
+ 6. **Видимый текст заведён во всех локалях.**
146
+ 7. **Правка вёрстки подтверждена замером**, а не взглядом, и снята при узком экране — паттерн
147
+ `browser-verification-measure`.
148
+ 8. **Правка публичной разметки проверена на прод-сборке по всем локалям** — паттерн
149
+ `seo-verify`.
150
+ 9. **Тело PR начинается строкой связи с задачей**, а метки, ревьювер и исполнитель стоят.
151
+ 10. **Заголовок PR несёт номер задачи и называет её сделанной** — тем же номером, что у задачи
152
+ и в имени ветки.
153
+ 11. **Очередь работ сходится.** Задача в очереди, с исполнителем и номером в заголовке; PR один
154
+ на задачу, и закрывает он её целиком.
155
+
156
+ Сразу после публикации задача переставляется в разбор, и сверка очереди прогоняется ещё раз: до
157
+ открытия PR колонку она не судит, а после открытия расхождение видит.
158
+
159
+ Сделанное рассуждением и сделанное замером в теле PR разводятся прямо: непроверенное, названное
160
+ проверенным, ревьювер принимает за проверенное.
161
+
162
+ ## Частые промахи
163
+
164
+ - **Добавление в индекс нескольких путей не добавляет ничего, если хоть один путь не
165
+ существует.** Команда обрывается на первом промахе целиком, а следующая правка последнего
166
+ коммита уносит в него всё, что осталось в индексе. Состав коммита читается сразу после него,
167
+ а не на разборе PR.
168
+ - **Задача, заведённая мимо команды, в очередь не попадает и гардом не отбивается** — он
169
+ смотрит команду, а не задачу. Ловится это только сверкой очереди.
170
+ - **Исполнитель у задачи сам не проставляется** ни при заведении через веб, ни при добавлении в
171
+ очередь.
172
+ - **Колонка сама не двигается** ни от заведения ветки, ни от открытия PR: очередь ветки не
173
+ видит вовсе, а связь с PR заполняет только поле связанных PR.
174
+ - **Постраничный обход очереди через общий флаг уходит в повтор первой страницы** — курсор
175
+ берётся из ответа руками, а полнота сверяется с общим числом элементов.
@@ -0,0 +1,82 @@
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`. Что при этом должно быть верно — закон `{{lawsDir}}/delivery.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - PR отмечен конфликтующим, и его надо вернуть к сливаемому состоянию.
15
+ - Главная ветка ушла вперёд, и ветку задачи надо подтянуть до проверок.
16
+ - Коммит переносится отдельным выбором.
17
+
18
+ ## Порядок
19
+
20
+ ```bash
21
+ git fetch origin
22
+ git merge origin/<главная ветка> --no-edit
23
+ git diff --name-only --diff-filter=U # что встало конфликтом
24
+ ```
25
+
26
+ Список конфликтов читается целиком до первого разрешения: род файла решает приём, и разные
27
+ файлы одного слияния разрешаются по-разному.
28
+
29
+ | Что встало конфликтом | Как разрешается |
30
+ | --------------------- | ------------------------------------------------------------------------------ |
31
+ | код | ловушка правила `git-workflow` про сторону-удаление; после — проверка повторов |
32
+ | спек домена | сохранением обеих сторон — правило `spec-driven`; после — проверка спеков |
33
+ | накопительный список | признаком отбора — паттерн `doc-style-sweep` |
34
+
35
+ ## Что дописала ветка, видно только от точки расхождения
36
+
37
+ Конфликтный маркер показывает место, а не правку: сторона ветки в нём — её допись вместе со
38
+ всем, что лежало в файле до неё.
39
+
40
+ ```bash
41
+ git diff "$(git merge-base origin/<главная ветка> HEAD)" HEAD -- <файл>
42
+ ```
43
+
44
+ ## Дописанное веткой сверяется с очередью работ, а не переносится по умолчанию
45
+
46
+ Раздел, который ветка дописала в накопительный список, к моменту слияния обычно уже стоит
47
+ задачей: ветка живёт неделями, а замеченный по ходу дефект заводится задачей сразу. Перенести
48
+ его второй раз — завести вторую запись об одной работе.
49
+
50
+ Когда задача несёт то же содержание, сторона ветки не переносится:
51
+
52
+ ```bash
53
+ git checkout --theirs <файл> && git add <файл>
54
+ ```
55
+
56
+ При слиянии `--theirs` — влитая главная ветка, а `--ours` — ветка задачи; при перебазировании
57
+ стороны меняются местами. Взятая не та сторона стирает работу молча.
58
+
59
+ ## Проверки после разрешения
60
+
61
+ Конфликт в текстах кода не задевает, и зелёная сборка про него ничего не говорит:
62
+
63
+ ```bash
64
+ grep -rn '^<<<<<<< \|^>>>>>>> ' --exclude-dir=node_modules --exclude-dir=.git .
65
+ ```
66
+
67
+ Следом гоняются проверки текстов, раскладки, повторов и очереди работ, а если конфликт задел
68
+ хуки — их сценарии. Коммит слияния подписывается так же, как любой другой, — паттерн
69
+ `git-workflow-commit`. После пуша состояние читается у самого PR, а не по своему дереву.
70
+
71
+ ## Тело открытого PR перечитывается после слияния
72
+
73
+ Отчёт описывал дерево на день, когда его написали. Вливание главной ветки меняет то, о чём он
74
+ утверждает: тело говорит про записи, которые главная ветка к тому времени уже разобрала.
75
+
76
+ ## Частые промахи
77
+
78
+ - «Сохранить обе стороны» применено ко всем файлам одинаково: в спеке это верно, в коде и в
79
+ накопительном списке — нет.
80
+ - Сторона ветки перенесена без сверки с очередью работ: одна работа стала двумя записями.
81
+ - После разрешения прогнана сборка, а проверки текстов — нет: конфликта в них сборке не видно.
82
+ - Тело PR оставлено прежним: ревьювер читает утверждение о дереве, которого больше нет.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: git-workflow-migration
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать при правке схемы хранилища и каталога миграций — прогон цепочки на одноразовом хранилище, написание файла миграции разницей, догон локального хранилища. Не брать для коммита и PR — это паттерн git-workflow-commit.
6
+ ---
7
+
8
+ # Миграция и прогон цепочки
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон `{{lawsDir}}/delivery.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Правится схема хранилища.
15
+ - Заводится или переименовывается каталог миграции.
16
+ - Ветка с новой миграцией готовится к слиянию.
17
+
18
+ ## Цепочка гоняется на одноразовом хранилище
19
+
20
+ Линтеры, тесты и сборки порядок миграций не трогают вовсе, а проверка соответствия схемы идёт
21
+ уже после слияния. Поэтому ветка прогоняется до слияния на пустом хранилище:
22
+
23
+ ```bash
24
+ docker run -d --rm --name <проба> -e <пароль> -p <порт>:<порт> <образ хранилища>
25
+ docker exec <проба> <проверка готовности> # накат до готовности падает на соединении
26
+ <адрес хранилища> npx <инструмент> migrate deploy
27
+ <адрес хранилища> npx <инструмент> migrate diff --from-config-datasource --to-schema <схема> --exit-code
28
+ docker stop <проба>
29
+ ```
30
+
31
+ Одноразовое хранилище, а не своё: гард запросов отбивает схемные команды, и завести базу под
32
+ проверку иначе нечем. Адрес ставится префиксом самой команды — экспорт между вызовами не живёт.
33
+
34
+ ## Файл миграции пишется тем же хранилищем
35
+
36
+ Команда разработчика для миграций не запускается: любое расхождение состояния она лечит
37
+ предложением сбросить хранилище, а в локальном лежат данные владельца. Файл берётся разницей
38
+ между накатанной цепочкой и схемой.
39
+
40
+ Каталог заводится **после** наката цепочки: пустой каталог, попавший в накат, помечается
41
+ применённым, и его содержимое на это хранилище уже не встанет.
42
+
43
+ ## Локальное хранилище догоняет ветку
44
+
45
+ Переименованная миграция остаётся в нём под прежним именем, и накат падает на «объект уже
46
+ существует». Состояние правится отметкой о применении, повторный накат его не чинит.
47
+
48
+ ## Частые промахи
49
+
50
+ - Метку времени ставит момент создания, а порядок применения лексикографический: миграция из
51
+ ветки, начатой раньше, встаёт перед той, от которой зависит. На существующем хранилище это
52
+ незаметно — падает только накат с нуля.
53
+ - Флаги инструмента не те, что в примерах из сети, и на неизвестный флаг он печатает справку, а
54
+ не строку ошибки. Какие флаги есть сейчас, смотрят в его собственной справке.
55
+ - Запись в боевое хранилище запрещена совсем: схема меняется миграцией через выкатку, данные —
56
+ через интерфейс.
57
+ - Строки адресуются по первичному ключу, а не по маске: удаление по маске уносит вместе с
58
+ пробными записями настоящие.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: git-workflow-restart
3
+ kind: pattern
4
+ rule: git-workflow
5
+ description: Паттерн правила git-workflow. Брать при ручном перезапуске прода — после правки окружения прода, при разборе выкатки, при подъёме контейнера на сервере. Команда с явным тегом образа по хешу коммита, способ узнать выкаченный хеш и чем сверять результат. Не брать для коммита и миграций — это паттерны git-workflow-commit и git-workflow-migration.
6
+ ---
7
+
8
+ # Ручной перезапуск прода
9
+
10
+ Паттерн правила `git-workflow`. Что при этом должно быть верно — закон `{{lawsDir}}/delivery.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Правилось окружение прода, и контейнер надо поднять заново.
15
+ - Разбирается, что именно сейчас выкачено.
16
+ - Контейнер поднимается на сервере руками, мимо выкатки по слиянию.
17
+
18
+ ## Команда обязана нести хеш коммита
19
+
20
+ Выкатка ставит образы по хешу коммита. Без явного тега подъём контейнера подставляет умолчание
21
+ «последний», а оно в реестре отстаёт от главной ветки — прод молча откатывается на старый образ
22
+ и при этом отвечает:
23
+
24
+ ```bash
25
+ IMAGE_TAG='<хеш>' docker compose -f <состав прода> --env-file <окружение> pull <службы>
26
+ IMAGE_TAG='<хеш>' docker compose -f <состав прода> --env-file <окружение> up -d --no-build --remove-orphans
27
+ ```
28
+
29
+ ## Хеш берётся до перезапуска
30
+
31
+ У выкаченного контейнера или у последнего слияния в главную ветку:
32
+
33
+ ```bash
34
+ docker inspect <контейнер> --format '{{.Config.Image}}'
35
+ ```
36
+
37
+ ## Сверка идёт по журналу, а не по коду ответа
38
+
39
+ Подмена образа видна только по пропавшим строкам нового кода: сводка запуска из журнала
40
+ исчезает, хотя строка «приложение поднялось» остаётся на месте. После перезапуска — тот же
41
+ осмотр образа и наличие ожидаемых строк в журнале.
42
+
43
+ ## Частые промахи
44
+
45
+ - Вывод «прод жив, значит выкатилось» — код ответа подмену образа не показывает.
46
+ - Переменные окружения, секреты и записи имён ставятся **до** слияния: слияние выкатывает
47
+ сразу, и ветка, зависящая от новой переменной, встаёт на проде до того, как переменную
48
+ заведут.
49
+ - Заход на сервер в автоматическом режиме режется правилом — нужен обычный.
@@ -0,0 +1,77 @@
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`. Что при этом должно быть верно — закон `{{lawsDir}}/lib-imports.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Символ переезжает из одной либы в другую.
15
+ - Домен переносится в новую раскладку.
16
+ - Общий код собирается из копий в одно место.
17
+
18
+ ## Начинать с планов
19
+
20
+ Решение о том, куда переезжает код, часто уже принято и записано, а принятое заново с ним
21
+ расходится — и откатывать приходится целиком. Поиск по документам делается до первой правки:
22
+
23
+ ```bash
24
+ grep -rn "<имя либы>" <каталог планов>/
25
+ ```
26
+
27
+ ## Порядок задаёт граф зависимостей, а не список в плане
28
+
29
+ Домен переносится после всех, от кого он зависит. Списки доменов в планах отсортированы по
30
+ важности, и следование им в лоб заставляет временно расширять границы — а каждая временная
31
+ строка в границах и есть та механическая проверка, ради которой нарезка затевалась.
32
+
33
+ ```bash
34
+ grep -rn "<алиас домена>" <каталоги кода> | sed 's/:.*//' | sort -u
35
+ ```
36
+
37
+ Рёбра выписываются поиском по алиасам домена и сортируются топологически.
38
+
39
+ ## Куда именно кладётся общее
40
+
41
+ Своя либа заводится тогда, когда ни одна существующая код не видит.
42
+
43
+ | Кому нужно | Куда |
44
+ | ---------------------------------------------- | ------------------------------------------------------------- |
45
+ | серверной стороне и фронту, без каркаса фронта | общая либа утилит |
46
+ | только фронтам, тянет каркас | либа платформы — служба и токен, либа общих компонентов — вид |
47
+ | предмету, у которого уже есть либа | в неё |
48
+ | всем доменам одной семьи | основание семейства |
49
+ | всей серверной стороне | тот слой утилит, что уже перечислен у каждого домена |
50
+
51
+ Новых строк в границах при таком переезде не появляется — кроме права видеть контракт, если код
52
+ его читает.
53
+
54
+ ## После переезда
55
+
56
+ 1. **README обеих либ.** У той, откуда файл ушёл, и у той, куда пришёл: README перечисляет, что
57
+ в либе лежит и кто её зовёт. Ни одна проверка эти тексты не читает.
58
+ 2. **Порядок импортов.** Переезд алиаса его ломает, и приходит это ошибкой линтера, а не
59
+ сборки. Автоправка есть только у линтера — в общий прогон с тестами и сборкой её флаг
60
+ передавать нельзя, падает весь вызов.
61
+ 3. **Линтер по всем затронутым проектам, а не по одному приложению.** Скрипт ошибается молча и
62
+ не так, как человек: строка импорта не переписывается, а исчезает целиком. Сборка одного
63
+ приложения до таких файлов не доходит — их находит только прогон по списку проектов.
64
+
65
+ ## Проверить
66
+
67
+ Проверка раскладки — и обязательно проверка повторов: перенос и есть тот момент, когда копия
68
+ остаётся на старом месте.
69
+
70
+ ## Частые промахи
71
+
72
+ - Новый адрес выбран без чтения планов — расходится с уже принятым решением.
73
+ - Порядок переноса взят из списка в плане — приходится временно расширять границы.
74
+ - README поправлен только у одной либы.
75
+ - Линтер прогнан по приложению, а не по списку затронутых проектов — пропавшие импорты не
76
+ видно.
77
+ - Копия осталась на старом месте, а проверка повторов не гонялась.
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: lib-layers-new
3
+ kind: pattern
4
+ rule: lib-layers
5
+ description: Паттерн правила lib-layers. Брать при заведении, переименовании или удалении либы — нужна ли либа вообще, генератор вместо голого вызова каркаса, тег, алиас, барель, README, чем добивать удаление. Перенос кода между уже существующими либами — паттерн lib-layers-move.
6
+ ---
7
+
8
+ # Завести или удалить либу
9
+
10
+ Паттерн правила `lib-layers`. Что при этом должно быть верно — закон `{{lawsDir}}/lib-imports.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Заводится новый домен или новый слой существующего домена.
15
+ - Либа переименовывается.
16
+ - Либа удаляется.
17
+
18
+ ## Сначала — нужна ли либа вообще
19
+
20
+ У домена есть экраны, состояние и запросы. Механика, общая нескольким доменам, доменом не
21
+ заводится: слои под неё останутся пустыми навсегда.
22
+
23
+ Признак: если ни слой экранов, ни слой состояния, ни слой обращения к серверу наполнить не из
24
+ чего — это утилиты, и им место в либе, которой они уже видны. У фронта такая либа есть всегда —
25
+ основание семейства; у серверной стороны — тот слой утилит, что уже перечислен у каждого
26
+ домена.
27
+
28
+ Домен, заведённый под механику, живёт девятью либами на три файла кода: семь из них пустые, и у
29
+ каждой свой манифест, свой конфиг прогонщика, барель, тег и алиас.
30
+
31
+ ## Заводится генератором, а не голым вызовом каркаса
32
+
33
+ Генератор кладёт манифест, конфиг типов, конфиг прогонщика и барель разом. Голый вызов каркаса
34
+ даёт конфиг прогонщика без настройки «успех при отсутствии тестов», и либа, у которой спек ещё
35
+ нет, роняет общий прогон строкой «файлов тестов не найдено». Проверка раскладки смотрит на
36
+ наличие файла, а не на его содержимое, поэтому такую либу она пропустит.
37
+
38
+ ## Что дописывается руками
39
+
40
+ 1. Тег в конфиге границ домена — один на либу, равный имени и пути.
41
+ 2. Алиас в конфиге путей.
42
+ 3. README либы: что в ней лежит и кто её зовёт.
43
+
44
+ Права на чужие либы выписываются строками с комментарием, зачем. Импорт, который «просто
45
+ заработал», означает, что тег ещё не сужен.
46
+
47
+ ## Удаление
48
+
49
+ Удаление средствами гита оставляет за собой то, что гит не отслеживал, — кэш сборщика внутри
50
+ удаляемого каталога, — и проверка раскладки продолжает видеть его как домен без слоёв.
51
+ Добивается обычным удалением каталога.
52
+
53
+ Следом снимаются тег, алиас и строки прав у тех, кто либу видел.
54
+
55
+ ## Проверить
56
+
57
+ Проверка раскладки смотрит слои, единственный тег, равный имени и пути, алиас, наличие
58
+ манифеста, конфига прогонщика и бареля, пустой список зависимостей у общей либы, границы
59
+ основания семейства и реэкспорты. Она стоит секунды — гоняется после любого создания,
60
+ переименования или удаления.
61
+
62
+ ## Частые промахи
63
+
64
+ - **Либа заведена под механику:** слои пустые и заполнять их нечем.
65
+ - **Голый вызов каркаса** — конфиг прогонщика без настройки «успех при отсутствии тестов», и
66
+ общий прогон краснеет.
67
+ - **Удаление без добивания каталога** — проверка видит призрак домена без слоёв.
68
+ - **Либа, которую никто не импортирует, не проверена ничем.** Линтер и тесты проверяют её саму,
69
+ а не договор с потребителем. Первый импортёр и есть первая проверка: слой моделей принимается
70
+ после сборки и живого прогона сценария, а не по зелёному линтеру с тестами.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: permissions-procedure
3
+ kind: pattern
4
+ rule: permissions
5
+ description: Паттерн правила permissions. Брать при заведении обработчика серверной стороны и при закрытии раздела интерфейса — метки доступа, отбивка без входа и без права, декларация пункта меню с правом и признаком незавершённости.
6
+ ---
7
+
8
+ # Объявление доступа
9
+
10
+ Паттерн правила `permissions`. Что при этом должно быть верно — закон `{{lawsDir}}/access.md`.
11
+
12
+ ## Когда брать
13
+
14
+ - Заводится обработчик серверной стороны.
15
+ - Раздел интерфейса закрывается правом.
16
+ - Обработчик должен отвечать гостю.
17
+
18
+ ## Метка на классе обработчика
19
+
20
+ Объявление ровно одно; без него приложение не поднимается:
21
+
22
+ ```typescript
23
+ @Injectable()
24
+ @ConnectProcedure()
25
+ @RequiresPermission('<ресурс>:<действие>')
26
+ export class LinkEntityProcedure implements IConnectProcedure<typeof DomainService.method.linkEntity> {
27
+ public readonly method: typeof DomainService.method.linkEntity = DomainService.method.linkEntity;
28
+ }
29
+ ```
30
+
31
+ | Метка | Кому доступно |
32
+ | -------------------------------- | ------------------------------------------------- |
33
+ | требование права | вошедшему с этим правом |
34
+ | требование входа | любому вошедшему; так живут профиль и выбор языка |
35
+ | публичный доступ | гостю без входа |
36
+ | публичный доступ с чтением входа | гостю, но токен читается, если он есть |
37
+
38
+ Аргумент — причина для читателя кода. Ни в ответ, ни в журнал она не уходит.
39
+
40
+ ## Отбивка
41
+
42
+ Перехватчик отвечает до тела обработчика:
43
+
44
+ - нет входа там, где вход нужен, — неаутентифицирован;
45
+ - вход есть, права нет — отказ в доступе;
46
+ - обработчик, о котором перехватчик ничего не знает, — тоже отказ, а не пропуск.
47
+
48
+ Сам обработчик решения о допуске не принимает.
49
+
50
+ ## Раздел интерфейса
51
+
52
+ Пункт меню и адрес закрываются одной декларацией: шапка берёт из неё подписи и адреса, страж —
53
+ права. Второго объявления этой связи не заводится.
54
+
55
+ Закрытие двухслойное: право пользователя и признак незавершённости раздела. Пункт с признаком
56
+ объявляется без прав и без адреса — право открывает экран, а экрана нет. Появится экран —
57
+ признак снимается, права добавляются.
58
+
59
+ ## Частые промахи
60
+
61
+ - **Два объявления доступа на одном обработчике:** приложение не поднимется, и увидено это
62
+ будет только при запуске.
63
+ - **Проверка права внутри тела:** право проверяется до тела.
64
+ - **Своё объявление прав рядом с маршрутами:** оно разойдётся с декларацией меню, и получится
65
+ «пункта не видно, а страница открывается».
66
+ - **Страж, повешенный на защищённую группу целиком:** он отрабатывает один раз за загрузку
67
+ страницы и переходов между разделами не видит.
68
+ - **Ожидание прав, которое роняется на отказе запроса:** с неизвестными правами не закрывается
69
+ ничего, и пустая шапка выхода владельцу не оставляет.