@rt-tools/agent-kit 0.3.0 → 0.5.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 (202) hide show
  1. package/README.md +194 -30
  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 +329 -0
  9. package/assets/checks/check-board.github.mjs +181 -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 +1086 -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 +106 -0
  21. package/assets/defaults/project.sh +204 -0
  22. package/assets/hooks/browser-device-id.sh +0 -0
  23. package/assets/hooks/browser-guard-device-id.sh +2 -1
  24. package/assets/hooks/browser-guard-no-asking.sh +27 -0
  25. package/assets/hooks/browser-guard-no-listing.sh +2 -1
  26. package/assets/hooks/browser-guard-no-other-drivers.sh +2 -1
  27. package/assets/hooks/browser-guard-require-select.sh +2 -1
  28. package/assets/hooks/commit-msg.sh +1 -1
  29. package/assets/hooks/constitution-index.sh +5 -4
  30. package/assets/hooks/dev-server-guard.sh +8 -6
  31. package/assets/hooks/docs-guard.sh +223 -37
  32. package/assets/hooks/git-guard-delivery.sh +171 -31
  33. package/assets/hooks/git-guard-main.sh +1 -0
  34. package/assets/hooks/git-guard-push-tests.sh +34 -13
  35. package/assets/hooks/glossary-load.sh +23 -0
  36. package/assets/hooks/grill-gate.sh +96 -0
  37. package/assets/hooks/lint-after-edit.sh +155 -30
  38. package/assets/hooks/qa-dataid-guard.sh +72 -32
  39. package/assets/hooks/reuse-first-guard.sh +105 -34
  40. package/assets/hooks/skill-gate-rearm.sh +1 -0
  41. package/assets/hooks/skill-gate.sh +75 -15
  42. package/assets/hooks/skill-loaded.sh +1 -0
  43. package/assets/hooks/sql-guard.sh +606 -56
  44. package/assets/hooks/task-context-load.sh +100 -0
  45. package/assets/hooks/task-flow-guard.sh +118 -0
  46. package/assets/laws/{access.md → application/access.md} +1 -4
  47. package/assets/laws/{locales.md → application/locales.md} +1 -3
  48. package/assets/laws/application/money.md +41 -0
  49. package/assets/laws/application/ownership.md +32 -0
  50. package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
  51. package/assets/laws/code-structure.md +7 -6
  52. package/assets/laws/delivery.md +53 -3
  53. package/assets/laws/entity-editing.md +49 -55
  54. package/assets/laws/entity-models.md +4 -14
  55. package/assets/laws/frontend-application.md +5 -5
  56. package/assets/laws/lib-imports.md +14 -1
  57. package/assets/laws/lists.md +33 -0
  58. package/assets/laws/navigation.md +40 -0
  59. package/assets/laws/project-documentation.md +27 -8
  60. package/assets/laws/reuse-first.md +26 -21
  61. package/assets/laws/shared-code.md +13 -1
  62. package/assets/laws/verifiability.md +30 -1
  63. package/assets/laws/work-conduct.md +59 -0
  64. package/assets/patterns/admin-lists-screen.md +131 -0
  65. package/assets/patterns/admin-nav-item.md +71 -0
  66. package/assets/patterns/angular-patterns-state.md +29 -22
  67. package/assets/patterns/api-layer-pair.md +40 -30
  68. package/assets/patterns/browser-verification-measure.md +41 -38
  69. package/assets/patterns/browser-verification-stand.md +106 -42
  70. package/assets/patterns/component-structure-new.md +33 -32
  71. package/assets/patterns/dependencies-upgrade.md +65 -0
  72. package/assets/patterns/doc-style-sweep.md +65 -28
  73. package/assets/patterns/doc-style-write.md +36 -33
  74. package/assets/patterns/entity-aside.md +136 -0
  75. package/assets/patterns/entity-models-new.md +124 -0
  76. package/assets/patterns/entity-store.md +91 -0
  77. package/assets/patterns/git-workflow-commit.azure.md +259 -0
  78. package/assets/patterns/git-workflow-commit.github.md +337 -0
  79. package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
  80. package/assets/patterns/git-workflow-merge.md +42 -25
  81. package/assets/patterns/git-workflow-migration.md +61 -31
  82. package/assets/patterns/git-workflow-restart.md +20 -20
  83. package/assets/patterns/lib-layers-move.md +50 -32
  84. package/assets/patterns/lib-layers-new.md +41 -29
  85. package/assets/patterns/ownership-scope-resolve.md +69 -0
  86. package/assets/patterns/permissions-procedure.md +35 -33
  87. package/assets/patterns/platform-access-di.md +39 -25
  88. package/assets/patterns/pricing-quote.md +71 -0
  89. package/assets/patterns/reuse-first-extend.md +22 -22
  90. package/assets/patterns/seo-page.md +52 -40
  91. package/assets/patterns/seo-verify.md +48 -29
  92. package/assets/patterns/shared-code-new.md +37 -31
  93. package/assets/patterns/spec-driven-domain.md +60 -37
  94. package/assets/patterns/spec-driven-rule.md +55 -40
  95. package/assets/patterns/styling-bem-component.md +43 -32
  96. package/assets/patterns/styling-bem-layout.md +30 -24
  97. package/assets/patterns/task-flow-close.md +154 -0
  98. package/assets/patterns/task-flow-resume.md +94 -0
  99. package/assets/patterns/task-flow-start.md +129 -0
  100. package/assets/patterns/testing-e2e.md +53 -51
  101. package/assets/patterns/testing-unit.md +70 -46
  102. package/assets/patterns/translations-key.md +32 -19
  103. package/assets/patterns/ts-procedure.md +24 -25
  104. package/assets/rules/angular-patterns.md +50 -27
  105. package/assets/rules/api-layer.md +46 -28
  106. package/assets/rules/browser-verification.md +67 -48
  107. package/assets/rules/component-structure.md +43 -27
  108. package/assets/rules/dependencies.md +66 -0
  109. package/assets/rules/doc-style.md +95 -39
  110. package/assets/rules/entity-conventions.md +78 -0
  111. package/assets/rules/entity-models.md +70 -0
  112. package/assets/rules/git-workflow.azure.md +116 -0
  113. package/assets/rules/git-workflow.github.md +123 -0
  114. package/assets/rules/git-workflow.gitlab.md +113 -0
  115. package/assets/rules/lib-layers.md +56 -30
  116. package/assets/rules/lists.md +73 -0
  117. package/assets/rules/navigation.md +78 -0
  118. package/assets/rules/ownership-scope.md +63 -0
  119. package/assets/rules/permissions.md +43 -25
  120. package/assets/rules/platform-access.md +57 -29
  121. package/assets/rules/pricing.md +64 -0
  122. package/assets/rules/reuse-first.md +57 -43
  123. package/assets/rules/seo.md +51 -30
  124. package/assets/rules/shared-code.md +51 -26
  125. package/assets/rules/spec-driven.md +107 -51
  126. package/assets/rules/styling-bem.md +54 -39
  127. package/assets/rules/task-flow.md +150 -0
  128. package/assets/rules/testing.md +78 -47
  129. package/assets/rules/translations.md +48 -31
  130. package/assets/rules/typescript-conventions.md +57 -27
  131. package/assets/skills/agent-kit.md +85 -0
  132. package/assets/skills/write-a-skill.md +108 -0
  133. package/assets/templates/gate-map.sh +23 -15
  134. package/assets/templates/implementation.md +14 -8
  135. package/assets/templates/pattern.md +1 -1
  136. package/assets/templates/project.sh +32 -19
  137. package/assets/templates/rule.md +2 -2
  138. package/assets/variants.json +20 -0
  139. package/assets/workflows/feature.js +134 -0
  140. package/assets/workflows/plan.js +150 -0
  141. package/bin/agent-kit.d.ts.map +1 -1
  142. package/bin/agent-kit.js +78 -5
  143. package/bin/agent-kit.js.map +1 -1
  144. package/bin/prompt.d.ts +5 -0
  145. package/bin/prompt.d.ts.map +1 -1
  146. package/bin/prompt.js +19 -7
  147. package/bin/prompt.js.map +1 -1
  148. package/index.d.ts +1 -0
  149. package/index.d.ts.map +1 -1
  150. package/index.js +1 -0
  151. package/index.js.map +1 -1
  152. package/lib/assets.d.ts +8 -3
  153. package/lib/assets.d.ts.map +1 -1
  154. package/lib/assets.js +13 -3
  155. package/lib/assets.js.map +1 -1
  156. package/lib/catalog.d.ts +52 -5
  157. package/lib/catalog.d.ts.map +1 -1
  158. package/lib/catalog.js +104 -16
  159. package/lib/catalog.js.map +1 -1
  160. package/lib/commands.d.ts +22 -1
  161. package/lib/commands.d.ts.map +1 -1
  162. package/lib/commands.js +202 -14
  163. package/lib/commands.js.map +1 -1
  164. package/lib/companion.d.ts +5 -1
  165. package/lib/companion.d.ts.map +1 -1
  166. package/lib/companion.js +29 -2
  167. package/lib/companion.js.map +1 -1
  168. package/lib/config.d.ts +26 -9
  169. package/lib/config.d.ts.map +1 -1
  170. package/lib/config.js +41 -15
  171. package/lib/config.js.map +1 -1
  172. package/lib/freshness.d.ts +14 -0
  173. package/lib/freshness.d.ts.map +1 -0
  174. package/lib/freshness.js +116 -0
  175. package/lib/freshness.js.map +1 -0
  176. package/lib/hooks-map.d.ts +27 -0
  177. package/lib/hooks-map.d.ts.map +1 -0
  178. package/lib/hooks-map.js +77 -0
  179. package/lib/hooks-map.js.map +1 -0
  180. package/lib/integrity.d.ts +36 -0
  181. package/lib/integrity.d.ts.map +1 -0
  182. package/lib/integrity.js +44 -0
  183. package/lib/integrity.js.map +1 -0
  184. package/lib/picker.d.ts +11 -1
  185. package/lib/picker.d.ts.map +1 -1
  186. package/lib/picker.js +44 -6
  187. package/lib/picker.js.map +1 -1
  188. package/lib/sync.d.ts +26 -0
  189. package/lib/sync.d.ts.map +1 -1
  190. package/lib/sync.js +59 -4
  191. package/lib/sync.js.map +1 -1
  192. package/lib/variants.d.ts +44 -0
  193. package/lib/variants.d.ts.map +1 -0
  194. package/lib/variants.js +82 -0
  195. package/lib/variants.js.map +1 -0
  196. package/package.json +1 -1
  197. package/rt-tools-agent-kit-0.5.0.tgz +0 -0
  198. package/assets/laws/admin-lists.md +0 -35
  199. package/assets/laws/admin-navigation.md +0 -38
  200. package/assets/patterns/git-workflow-commit.md +0 -175
  201. package/assets/rules/git-workflow.md +0 -106
  202. package/rt-tools-agent-kit-0.3.0.tgz +0 -0
@@ -2,63 +2,82 @@
2
2
  name: seo-verify
3
3
  kind: pattern
4
4
  rule: seo
5
- description: Паттерн правила seo. Брать после любой правки, задевающей публичную разметку, теги головы документа или маршруты — сборка, поднятие сервера отдачи страниц, проверка отданной разметки по всем локалям, карта сайта, кэшируемость перенаправления. Не брать для самой правки разметки — это паттерн seo-page.
5
+ description: Паттерн правила seo. Брать после любой правки, задевающей разметку публичного сайта, meta или маршруты — готовые команды сборки, поднятия SSR и проверки отданного HTML по локалям, карты сайта и кэшируемости перенаправления. Не брать для самой правки разметки — это паттерн seo-page.
6
6
  ---
7
7
 
8
8
  # Проверка разметки на прод-сборке
9
9
 
10
- Паттерн правила `seo`. Что при этом должно быть верно — закон `{{lawsDir}}/search-visibility.md`.
10
+ Паттерн правила `seo`. Что при этом должно быть верно — закон
11
+ `docs/constitution/application/search-visibility.md`.
11
12
 
12
13
  ## Когда брать
13
14
 
14
- После любой правки, задевающей публичную разметку, теги головы документа, маршруты, серверную
15
- точку входа, правила обхода или конфиг прокси.
15
+ После любой правки, задевающей разметку сайта, `meta`, маршруты, `server.ts`, `robots.txt`
16
+ или `deploy/nginx.conf`.
16
17
 
17
- ## Сервер разработки здесь не показатель
18
+ ## Дев-сервер здесь не показатель
18
19
 
19
- Теги ставятся при отдаче страницы сервером. В режиме разработки этот путь другой, поэтому
20
- проверка идёт на собранном приложении с поднятым сервером отдачи страниц.
20
+ Теги ставятся при отдаче страницы сервером. В дев-режиме этот путь другой, поэтому проверка
21
+ идёт на собранном приложении с поднятым SSR.
21
22
 
22
- Сервер отдачи страниц отвечает отказом на чужое имя хоста — запросы идут с явным заголовком
23
- хоста.
23
+ ```bash
24
+ npx nx build site
25
+ PORT={{prodSitePort}} node dist/apps/site/server/server.mjs &
26
+ ```
27
+
28
+ Порт {{prodSitePort}} — тот же, что берёт стенд; дев-серверы владельца на {{sitePort}} и {{adminPort}} при этом не
29
+ трогаются. Angular SSR отвечает `400` на чужой `Host`, поэтому запросы идут с
30
+ `-H "Host: localhost"`.
24
31
 
25
- ## Что смотреть в отданной разметке
32
+ ## Что смотреть в отданном HTML
26
33
 
27
34
  ```bash
28
- for locale in "" <остальные локали>; do
29
- printf '%-10s ' "${locale:-<по умолчанию>}"
30
- curl -s -H "Host: localhost" "http://localhost:<порт>/${locale}<путь>" \
35
+ for locale in "" ru/ de/ zh-Hans/ zh-Hant/ ko/ th/ hi/; do
36
+ printf '%-10s ' "${locale:-en}"
37
+ curl -s -H "Host: localhost" "http://localhost:{{prodSitePort}}/${locale}<адрес страницы>" \
31
38
  | grep -c -E '<title>|name="description"|property="og:|rel="canonical"|hreflang=|application/ld\+json'
32
39
  done
33
40
  ```
34
41
 
35
- В ответе каждой локали должны быть заголовок, описание, набор тегов соцсетей, канонический
36
- адрес, полный набор языковых ссылок вместе со ссылкой по умолчанию и блок структурированных
37
- данных.
42
+ В ответе каждой локали должны быть `<title>`, `description`, набор `og:*`, `canonical`,
43
+ полный набор `hreflang` плюс `x-default` и блок `application/ld+json`.
38
44
 
39
- Отдельно проверяется, что канонический адрес ведёт на **свой** язык, а не на локаль по
40
- умолчанию.
45
+ Отдельно проверяется, что `canonical` ведёт на **свой** язык, а не на локаль по умолчанию:
46
+
47
+ ```bash
48
+ curl -s -H "Host: localhost" http://localhost:{{prodSitePort}}/de/<адрес страницы> \
49
+ | grep -o 'rel="canonical" href="[^"]*"'
50
+ ```
41
51
 
42
52
  ## Карта сайта
43
53
 
44
- Карта строится из живых данных, а не из файла. Пустой ответ означает, что не поднялся запрос за
45
- записями, это отказ, а не «записей нет».
54
+ ```bash
55
+ curl -s -H "Host: localhost" http://localhost:{{prodSitePort}}/sitemap.xml | head -20
56
+ ```
57
+
58
+ Карта строится из живых данных, а не из файла. Пустой ответ означает, что не поднялся запрос
59
+ за объектами, — это отказ, а не «объектов нет».
46
60
 
47
61
  ## Кэшируемость перенаправления
48
62
 
49
- Проверяется только на стенде с настоящим конфигом прокси: голый сервер отдачи страниц отдаёт
50
- заголовки, но не показывает, попадёт ли ответ в кэш.
63
+ Проверяется только на стенде с настоящим `deploy/nginx.conf`: голый SSR отдаёт заголовки, но
64
+ не показывает, попадёт ли ответ в кэш.
51
65
 
52
66
  ```bash
53
- curl -sI http://<стенд>/<прежний адрес> | grep -i -E 'HTTP/|location|cache-control|x-cache'
67
+ curl -sI http://<стенд>/<прежний-slug> | grep -i -E 'HTTP/|location|cache-control|x-cache'
54
68
  ```
55
69
 
56
- Ответ обязан быть постоянным перенаправлением, нести срок жизни и попадать в кэш.
70
+ Ответ обязан быть `301`, нести `Cache-Control` со сроком и попадать в кэш. Некэшируемое
71
+ перенаправление не вытесняет старую запись, и гость видит прежнюю страницу до суток.
72
+
73
+ ## Тексты
74
+
75
+ `title` и `description` берутся из словарей во всех локалях перевода. Непереведённый ключ уезжает
76
+ в выдачу по-английски — полноту словарей держит `npx nx test common-i18n`.
57
77
 
58
78
  ## Частые промахи
59
79
 
60
- - **Проверка на сервере разработки:** теги ставит другой путь, и результат ничего не говорит о
61
- проде.
62
- - **Проверена одна локаль:** ветка маршрутов, забытая для остальных, отдаёт отказ и поисковику,
63
- и читателю.
64
- - **Заголовки смотрели на голом сервере:** кэш и перенаправления живут в прокси.
80
+ - Проверка в дев-сервере: разметку там ставит другой путь, и отсутствие тега не видно.
81
+ - Проверка одной локали: расходится обычно та, которую не смотрели.
82
+ - Проверка кэша без nginx: заголовки видны, попадание в кэш нет.
83
+ - Вывод по коду ответа: `200` приходит и со страницы без разметки.
@@ -2,29 +2,30 @@
2
2
  name: shared-code-new
3
3
  kind: pattern
4
4
  rule: shared-code
5
- description: Паттерн правила shared-code. Брать, когда заводится новое число-настройка, общая функция или общий тип, который должны одинаково понимать все приложения — куда класть, как объявить, как сверить строку с набором и как убедиться, что копия не осталась на старом месте.
5
+ description: Паттерн правила shared-code. Брать, когда заводится новое число-настройка, общая функция или общий тип, который должны одинаково понимать сайт, админка и бэкенд — куда класть, как объявить, как сверить строку с набором и как убедиться, что копия не осталась на старом месте.
6
6
  ---
7
7
 
8
8
  # Новое общее заводится так
9
9
 
10
- Паттерн правила `shared-code`. Что при этом должно быть верно — закон `{{lawsDir}}/shared-code.md`.
10
+ Паттерн правила `shared-code`. Что при этом должно быть верно — закон
11
+ `docs/constitution/shared-code.md`.
11
12
 
12
13
  ## Когда брать
13
14
 
14
15
  - Появилось число-настройка: предел, размер, длительность.
15
- - Появилась функция без каркаса, нужная обеим сторонам.
16
+ - Появилась функция без фреймворка, нужная обеим сторонам.
16
17
  - Значение приходит строкой и должно быть сверено с конечным набором.
17
18
 
18
19
  ## Куда класть
19
20
 
20
- | Что | Куда |
21
- | -------------------------------------------- | ------------------------------------------- |
22
- | число или функция без каркаса | общая либа утилит, файл по предмету |
23
- | готовый тип или набор значений | берётся из общего пакета, не переписывается |
24
- | токен внедрения, общий двум фронтовым семьям | либа платформы |
21
+ | Что | Куда |
22
+ | ------------------------------------- | ----------------------------------------------- |
23
+ | число или функция без фреймворка | `libs/common/util`, файл по предмету |
24
+ | готовый тип или набор значений | берётся из `@rt-tools/utils`, не переписывается |
25
+ | токен DI, общий двум фронтовым семьям | `libs/common/platform` |
25
26
 
26
- Файл выбирается по предмету, а не по роду («константы», «функции»): предметный файл читается
27
- целиком, свалка по роду — никогда. Дальше — строка в барель.
27
+ Файл выбирается по предмету: `const/list.const.ts`, `functions/list-selection.util.ts`.
28
+ Дальше — строка в барель `libs/common/util/src/index.ts`.
28
29
 
29
30
  ## Число объявляется один раз и без довода
30
31
 
@@ -33,48 +34,53 @@ export const DEFAULT_PAGE_SIZE: number = 20;
33
34
  ```
34
35
 
35
36
  ```typescript
36
- ✗ export function listPageOf(query: IListQuery | undefined, defaultPageSize: number): IListPage
37
- ✓ export function listPageOf(query: IListQuery | undefined): IListPage
37
+ ✗ export function listPageOf(query: ListQuery | undefined, defaultPageSize: number): IListPage
38
+ ✓ export function listPageOf(query: ListQuery | undefined): IListPage
38
39
  ```
39
40
 
40
- Пока умолчание передаётся доводом, домен вправе назвать своё число — и называет, расходясь с
41
- соседним на единицу, которую никто не заметит.
41
+ Пока умолчание передаётся доводом, домен вправе назвать своё число — так у промокодов
42
+ появилось `25` против `20` у остальных списков.
42
43
 
43
44
  ## Строка сверяется с набором, а не приводится к типу
44
45
 
45
- Приведение принимает любую строку. Сверку делает общая функция, а что делать с промахом, решает
46
- вызывающий:
46
+ Приведение принимает любую строку. Сверку делает общая пара функций, а что делать с промахом,
47
+ решает вызывающий.
47
48
 
48
49
  ```typescript
49
- const operator: TFilterOperator | null = listFilterOperatorOf(filter.operatorType);
50
+ const operator: FilterOperatorType | null = listFilterOperatorOf(filter.operatorType);
50
51
  if (!operator) {
51
- throw new RequestError(`filter operator is required: ${filter.propertyName}`);
52
+ throw new ConnectError(`filter operator is required: ${filter.propertyName}`, Code.InvalidArgument);
52
53
  }
53
54
  ```
54
55
 
55
56
  ```typescript
56
- const direction: TListSortOrder = listSortOrderOf(rawDirection) ?? LIST_SORT_ORDER_ENUM.ASC;
57
+ const direction: ListSortOrderType = listSortOrderOf(rawDirection) ?? LIST_SORT_ORDER_ENUM.ASC;
57
58
  ```
58
59
 
59
- Сервер отбивает запрос, экран берёт умолчание. Общий переводчик здесь не годится: он подал бы
60
+ Сервер отбивает запрос, экран берёт умолчание. Общий маппер здесь не годится: он подал бы
60
61
  промах умолчанием, и клиент получил бы отбор, которого не просил.
61
62
 
62
- Помощник приведения типов для этого тоже не годится — значение вне набора он пишет в журнал и
63
- возвращает строкой.
63
+ `typeCast.getAsType` для этого тоже не годится — значение вне набора он пишет в консоль и
64
+ возвращает строкой `'unknown'`.
64
65
 
65
66
  ## Проверить, что копия не осталась
66
67
 
67
- Проверка повторов падает на четырёх признаках: одно имя из двух либ, два перечисления с
68
- одинаковым набором членов, число-настройка под одним именем в двух либах, перечисление,
69
- повторяющее набор из общего пакета.
68
+ ```bash
69
+ npm run check:dupes
70
+ ```
71
+
72
+ Проверка падает на четырёх признаках: одно имя из двух либ, два перечисления с одинаковым
73
+ набором членов, число-настройка под одним именем в двух либах, перечисление, повторяющее набор
74
+ из `@rt-tools/utils`.
70
75
 
71
- Накопленное лежит в списке исключений и отказом не считается. Список только сокращается: новая
72
- строка в нём означает, что повтор завели уже после проверки.
76
+ Накопленное лежит в `tools/dupes-allowlist.json` под ключом `debt` и отказом не считается.
77
+ Список только сокращается: новая строка в нём означает, что повтор завели уже после проверки.
73
78
 
74
79
  ## Частые промахи
75
80
 
76
- - Своё перечисление с теми же членами, что уже есть в общем пакете, — копия, даже если имена
77
- разошлись.
81
+ - Своё перечисление с теми же членами, что уже есть в `@rt-tools/utils`, — копия, даже если
82
+ имена разошлись.
78
83
  - Умолчание, переданное доводом, — домен назовёт своё число, и разъезд будет молчаливым.
79
- - Ту же логику, написанную заново под другим именем, проверка не ловит.
80
- - Строковая настройка и таблица соответствий не учитываются вовсе.
84
+ - Ту же логику, написанную заново под другим именем, проверка не ловит и ловить не будет —
85
+ такой повтор находит только тот, кто читает правку.
86
+ - Строковая настройка и таблица соответствий не учитываются вовсе — долг `Q-S-2`.
@@ -2,48 +2,59 @@
2
2
  name: spec-driven-domain
3
3
  kind: pattern
4
4
  rule: spec-driven
5
- description: Паттерн правила spec-driven. Брать при заведении или правке спека домена раскладка файлов, обязательные разделы, форма правила и его привязки, форма сценария, порядок работы от спека к коду. Не брать для заведения закона, правила или паттерна — это паттерн spec-driven-rule.
5
+ description: Паттерн правила spec-driven. Брать при заведении или правке спека домена в docs/specs обязательные разделы, форма сценария, привязка правила к коду, порядок работы от спека к коду. Не брать для заведения закона, правила или паттерна — это паттерн spec-driven-rule.
6
6
  ---
7
7
 
8
8
  # Спек домена
9
9
 
10
10
  Паттерн правила `spec-driven`. Что при этом должно быть верно — закон
11
- `{{lawsDir}}/project-documentation.md`.
11
+ `docs/constitution/project-documentation.md`.
12
12
 
13
13
  ## Когда брать
14
14
 
15
- - Заводится новый домен или фича, которой ещё нет.
16
- - Правится контракт — спеки задетых доменов едут той же веткой.
15
+ - Заводится новый домен или фича в `proposed/`.
16
+ - Правится `.proto` — спеки задетых доменов едут той же веткой.
17
17
  - Замечено расхождение спека с кодом.
18
18
 
19
19
  ## Раскладка
20
20
 
21
21
  ```
22
- <спеки>/<домен>/
22
+ docs/specs/<домен>/
23
23
  spec.md — как домен работает
24
24
  implementation.md — таблица «правило → файл:символ»
25
25
  scenarios.md — сценарии SC-<ПРЕФИКС>-<НОМЕР>
26
+ <поддомен>/ — свой spec.md, implementation.md и scenarios.md
26
27
  proposed/<фича>/ — только то, чего ещё нет
27
28
  ```
28
29
 
30
+ Шаблон — `docs/specs/_template/spec.md`, указатель с префиксами — `docs/specs/README.md`.
31
+
32
+ Поддомен спрашивается наравне с доменом: те же обязательные разделы, тот же компаньон рядом,
33
+ та же связь сценариев с тестами. Домен, у которого половина поддоменов описана, а половина
34
+ заведена пустыми каталогами, зелёным не бывает.
35
+
29
36
  ## Обязательные разделы
30
37
 
31
- Набор разделов задан заранее и сверяется дословно: зачем, терминология, правила, что не входит,
32
- контракт с кодами отказов, данные, экраны и состояния, сквозные требования, решения. «Не
33
- применимо» законный ответ, отсутствие раздела нет: сквозные требования вспоминаются
34
- постфактум именно тогда, когда для них не заведено места.
38
+ `## Зачем` · `## Терминология` с подразделом `### Как это называется в интерфейсе` ·
39
+ `## Правила` · `## Что не входит` · `## Контракт` с подразделом `### Коды отказов` ·
40
+ `## Данные` · `## Экраны и состояния` · `## Сквозные требования` с четырьмя подразделами
41
+ `### Локали`, `### SEO`, `### Мобильная раскладка`, `### Мультиобъектность` · `## Решения` ·
42
+ `## Открытые вопросы` · `## История изменений`.
43
+
44
+ Текст заголовка сверяется дословно. «Не применимо» — законный ответ, отсутствие раздела — нет.
35
45
 
36
- Шапка несёт статус, префикс сценариев, зависимости от других доменов, строку с законами,
37
- которые домен применяет, и строку с корнями либ, чьи обработчики он обслуживает.
46
+ Шапка несёт статус, дату ревизии, префикс сценариев, зависимости от других доменов, строку
47
+ `**Законы:**` — законы, которые домен применяет, и строку `**Процедуры:**` корни либ, чьи
48
+ процедуры домен обслуживает.
38
49
 
39
50
  ```markdown
40
- **Зависимости:** `<домен>` (что берётся), `<домен>` (что берётся)
41
- **Законы:** `access`, `locales`, `shared-code`
42
- **Обработчики:** `<корень либы>`
51
+ **Зависимости:** `pricing` (сумма заявки), `availability` (занятость дат)
52
+ **Законы:** `access`, `locales`, `money`, `ownership`
53
+ **Процедуры:** `libs/api/<домен>`
43
54
  ```
44
55
 
45
- Закон, названный где-нибудь в тексте спека, обязан стоять в этой строке: связь сверяется в обе
46
- стороны.
56
+ Закон, названный где-нибудь в тексте спека, обязан стоять в этой строке: связь сверяется в
57
+ обе стороны.
47
58
 
48
59
  ## Правило и его привязка
49
60
 
@@ -56,45 +67,57 @@ description: Паттерн правила spec-driven. Брать при зав
56
67
  Привязка живёт в `implementation.md` рядом, ключ связи — сам текст правила:
57
68
 
58
69
  ```markdown
59
- | Правило | Где исполняется |
60
- | ------------------------------------- | ----------------- |
61
- | Применяется одна максимальная скидка. | `<путь>:<символ>` |
70
+ | Правило | Где исполняется |
71
+ | ------------------------------------- | ------------------------------------------------------------------ |
72
+ | Применяется одна максимальная скидка. | `libs/api/<домен>/util/src/lib/quote.calculator.ts:calculateQuote` |
62
73
  ```
63
74
 
64
- Правило, которому места в коде не нашлось, — намерение: ему место в открытых вопросах, а не
65
- формальный якорь.
75
+ Правило, которому места в коде не нашлось, — намерение: ему место в «Открытых вопросах» как
76
+ `Q-N`, а не формальный якорь.
66
77
 
67
78
  ## Сценарий
68
79
 
69
80
  ```markdown
70
- ### SC-<ПРЕФИКС>-19 — подтверждение на занятые даты отбивается
81
+ ### SC-BK-19 — подтверждение на занятые даты отбивается
71
82
 
72
- Дано у записи есть подтверждённая соседняя на пересекающиеся даты
83
+ Дано у объекта есть подтверждённая бронь на пересекающиеся даты
73
84
  Когда владелец подтверждает заявку
74
- Тогда отказ подаётся владельцу как занятые даты, а не как ошибка хранилища
85
+ Тогда отказ подаётся владельцу как занятые даты, а не как ошибка базы
75
86
  ```
76
87
 
77
88
  Идентификатор ставится в начало заголовка теста, через тире. Сценарий без теста помечается
78
- отметкой с причиной, сценарий с неполным тестом — отметкой о частичном покрытии.
89
+ `Не покрыто: <причина>`, сценарий с неполным тестом — `Покрытие: частичное <чего не
90
+ хватает>`.
79
91
 
80
92
  ## Порядок работы
81
93
 
82
94
  1. Задача заводится сценариями: что станет верно, когда работа закончится.
83
- 2. Спек домена правится **до** кода.
95
+ 2. Спек домена (или `proposed/<фича>/`) правится **до** кода.
84
96
  3. Код пишется под сценарии, тесты называются их идентификаторами.
85
- 4. Проверка спеков — до пуша.
97
+ 4. `npm run check:specs` — до пуша.
86
98
  5. Приёмка идёт по сценариям, а не по пересказу правки.
87
99
 
88
100
  ## Частые промахи
89
101
 
90
- - **Список шагов в спеке:** шаги артефакт сессии, им место в ветке или в описании PR.
91
- - **Скопированная из контракта таблица полей:** источник один, а компилируется из двух только
92
- одна.
93
- - **Колонки и индексы в спеке:** они в схеме хранилища, а в спеке остаётся правило, которое
102
+ - Выросший домен делят на новые домены, а не на поддомены: новый домен приходится заводить в
103
+ указателе, сверять с кодом отдельно и объяснять, чем он соседу не поддомен, — а поддомен
104
+ остаётся в своём домене и наследует его контракт. Соседний домен заводится только тогда,
105
+ когда предмет живёт своей сущностью. Границу проводит владелец: деление переписывает номера
106
+ во всех заголовках тестов домена, и вернуть его назад тем же движением нельзя.
107
+ - Счётчик правил или сценариев в указателе доменов: он пересчитывается при каждой правке
108
+ любого спека, и через год большая часть таких чисел молча описывает позавчерашний спек.
109
+ Указатель держит домен, префикс и одну строку «о чём».
110
+ - `tasks.md` в спеке: шаги — артефакт сессии, им место в ветке или в описании PR.
111
+ - Скопированная из контракта таблица полей: источник — `libs/common/proto/proto/<область>/v1/`,
112
+ и компилируется из двух только одна.
113
+ - Колонки и индексы в спеке: они в `prisma/schema.prisma`, а в спеке остаётся правило, которое
94
114
  ограничение выражает.
95
- - **Место, где правило исполняется, внутри текста правила:** оно меняется при первом же
96
- переносе, и для него заведён отдельный файл.
97
- - **Отметка о непокрытом при существующем тесте** — отказ: долг закрыли, а отметку не сняли.
98
- - **Закон, названный в тексте, но забытый в шапке:** по закону тогда не узнать, какие домены на
99
- нём стоят.
100
- - **Правка контракта без спеков задетых доменов** гард документов отбивает такой коммит.
115
+ - Место, где правило исполняется, внутри текста правила: оно меняется при первом рефакторинге,
116
+ и для него заведён `implementation.md`.
117
+ - Пометка «Не покрыто» при существующем тесте — отказ: долг закрыли, а отметку не сняли.
118
+ - Пометка «Не покрыто» читается дословно и с начала строки. Любое слово между ней и двоеточием
119
+ «Не покрыто, и прогоном не покрывается вовсе: …» — и сценарий считается непомеченным вовсе,
120
+ а причина, ради которой пометку и писали, до отчёта не доезжает.
121
+ - Закон, названный в тексте, но забытый в строке `**Законы:**`: по закону тогда не узнать,
122
+ какие домены на нём стоят.
123
+ - Правка `.proto` без спеков задетых доменов: `docs-guard` отбивает такой коммит.
@@ -2,13 +2,13 @@
2
2
  name: spec-driven-rule
3
3
  kind: pattern
4
4
  rule: spec-driven
5
- description: Паттерн правила spec-driven. Брать при заведении или правке закона, правила или паттерна — готовые шапки, набор разделов каждого слоя, таблица привязки, признак того, что правило пора делить. Не брать для спека домена — это паттерн spec-driven-domain.
5
+ description: Паттерн правила spec-driven. Брать при заведении или правке закона в docs/constitution, правила или паттерна в .claude/skills — готовые шапки, набор разделов каждого слоя, таблица привязки, признак того, что правило пора делить. Не брать для спека домена — это паттерн spec-driven-domain.
6
6
  ---
7
7
 
8
8
  # Закон, правило и паттерн
9
9
 
10
10
  Паттерн правила `spec-driven`. Что при этом должно быть верно — закон
11
- `{{lawsDir}}/project-documentation.md`.
11
+ `docs/constitution/project-documentation.md`.
12
12
 
13
13
  ## Когда брать
14
14
 
@@ -18,36 +18,51 @@ description: Паттерн правила spec-driven. Брать при зав
18
18
 
19
19
  ## Закон
20
20
 
21
- `{{lawsDir}}/<закон>.md`. О проекте не знает ничего: ни путей, ни имён файлов, ни привязок.
22
- Признак закона: попытка положить статью в один спек заставляет повторить то же самое ещё в
23
- двух.
21
+ `docs/constitution/<закон>.md`. О проекте не знает ничего: ни путей, ни имён файлов, ни
22
+ привязок. Признак закона: попытка положить правило в спек домена заставляет повторить то же
23
+ самое ещё в двух.
24
24
 
25
- Разделы: вводный абзац без заголовка, затем `## Статьи`. Обязательны статьи их и сверяет
26
- проверка.
25
+ Слой выбирается по одному вопросу: останется ли статья верной в приложении, где нет ни денег,
26
+ ни локалей перевода, ни второй владеющей сущности. Останется — закон живёт в корне; не
27
+ останется — это закон приложения, и он кладётся в `docs/constitution/application/<закон>.md`. Имя закона одно на
28
+ оба слоя: ни `law:` в шапке правила, ни `**Законы:**` в шапке спека слоя не называют, а два
29
+ закона с одним именем развели бы правило и его закон между собой.
27
30
 
28
- Ни истории правок, ни доводов о том, почему когда-то выбрали так, в законе нет. Историю держит
29
- система контроля версий, а довод с отвергнутой альтернативой свойство работы, а не продукта:
30
- ему место в «Ловушках» правила под этим законом, где и путям к файлам можно. Утверждение,
31
- которое нельзя написать как «верно всегда», статьёй не становится вовсе.
31
+ Разделы: `## Зачем` (без заголовка, вводным абзацем) · `## Статьи` · `## Открытые вопросы`.
32
+ Обязательны только «Статьи» их и сверяет проверка. «Открытые вопросы» заводятся, когда
33
+ вопрос есть, и стираются вместе с последним закрытым: закрытый вопрос из закона убирается, а
34
+ не превращается в пустой раздел.
35
+
36
+ Ни истории правок, ни доводов о том, почему когда-то выбрали так, в законе нет. Историю
37
+ держит система контроля версий, а довод с отвергнутой альтернативой — свойство работы, а не
38
+ продукта: ему место в «Ловушках» правила под этим законом, где и путям к файлам можно.
39
+ Утверждение, которое нельзя написать как «верно всегда», статьёй не становится вовсе.
32
40
 
33
41
  ```markdown
34
- # Поставка
42
+ # Закон о поставке
35
43
 
36
44
  Как правка доезжает до работающего приложения. …
37
45
 
46
+ **Ревизия:** 2026-08-05
47
+
38
48
  ## Статьи
39
49
 
40
50
  - **Выкатывается образ того коммита, который выкатывают.** Умолчание «последний» отстаёт от
41
51
  главной ветки, и приложение молча возвращается к прежней версии, продолжая отвечать.
42
52
  ```
43
53
 
44
- Поведение кода законом не является: «стор отвечает булевым», «метод называется так-то» этого
54
+ Раздел `## Открытые вопросы` заводится, когда вопрос есть, и стирается вместе с последним
55
+ закрытым. Вопрос называется `Q-<буква закона>-<номер>`, говорит, что решение изменит, и несёт
56
+ дату заведения; номер после закрытия не переиспользуется.
57
+
58
+ Поведение кода законом не является: «стор отвечает булевым», «метод называется `save`» — этого
45
59
  не видит ни гость, ни владелец. Граница простая: закон описывает то, что видно снаружи
46
- приложения.
60
+ приложения. Исключение — статья об устройстве кода, которую сверяет машина: якоря читаются
61
+ только под `docs/specs/` и `docs/constitution/`.
47
62
 
48
63
  ## Правило
49
64
 
50
- `{{rulesDir}}/<правило>/SKILL.md`. Говорит, каким приёмом закон исполняется; на один закон их
65
+ `.claude/skills/<правило>/SKILL.md`. Привязывает закон к этому проекту; на один закон их
51
66
  бывает несколько.
52
67
 
53
68
  ```markdown
@@ -55,28 +70,28 @@ description: Паттерн правила spec-driven. Брать при зав
55
70
  name: git-workflow
56
71
  kind: rule
57
72
  law: delivery
58
- description: Правило под закон «Поставка». Брать на … Готовый код — в паттернах … Чем это названо здесь — в implementation.md рядом.
73
+ description: Правило под «Закон о поставке». Брать на … Готовый код — в паттернах …
59
74
  ---
60
75
  ```
61
76
 
62
- Разделы: `## Когда берётся` · `## Что здесь действует` · `## Паттерны` · `## Ловушки`.
77
+ Разделы: `## Как это называется здесь` · `## Где это лежит` · `## Как закон применяется
78
+ здесь` · `## Чего из закона здесь нет` · `## Паттерны` · `## Ловушки`.
63
79
 
64
- Имён этого дерева в правиле нет оно переносимо ровно поэтому. Как что называется здесь и где
65
- лежит, пишется рядом, в `implementation.md`, и оттуда же идёт привязка статей к коду:
80
+ Сверяется только `## Как закон применяется здесь`: каждый его пункт начинается жирной фразой,
81
+ и у каждой жирной фразы есть строка в `implementation.md` рядом.
66
82
 
67
83
  ```markdown
68
- | Статья | Где исполняется |
69
- | --------------------------------------------------------------- | ----------------------------- |
70
- | Образы выкатываются по хешу коммита, а не по метке «последний». | `<состав прода>:<переменная>` |
84
+ | Статья | Где исполняется |
85
+ | -------------------------------------------------------------- | ----------------------------------- |
86
+ | Образы выкатываются по sha коммита, а не по метке «последний». | `docker-compose.prod.yml:IMAGE_TAG` |
71
87
  ```
72
88
 
73
- Каждый пункт раздела `## Что здесь действует` начинается жирной статьёй, и у каждой статьи есть
74
- строка в компаньоне. Утверждение, которому места в коде не нашлось, в этот раздел не ставится:
75
- оно уходит прозой в «Ловушки» или статьёй в закон.
89
+ Утверждение, которому места в коде не нашлось, в этот раздел не ставится: оно уходит прозой в
90
+ «Ловушки» или вопросом `Q-N` в закон.
76
91
 
77
92
  ## Паттерн
78
93
 
79
- `{{rulesDir}}/<правило>-<что>/SKILL.md`. Минимум один на правило.
94
+ `.claude/skills/<правило>-<что>/SKILL.md`. Минимум один на правило.
80
95
 
81
96
  ```markdown
82
97
  ---
@@ -87,26 +102,26 @@ description: Паттерн правила git-workflow. Брать … Не б
87
102
  ---
88
103
  ```
89
104
 
90
- Разделы: `## Когда брать` · готовый код · `## Частые промахи`. Компаньона у паттерна нет:
91
- сверять готовый код с ним самим нечем.
105
+ Разделы: `## Когда брать` · готовый код · `## Частые промахи`. Привязки у паттерна нет:
106
+ проверка его не сверяет, потому что сверять готовый код с ним самим нечем.
92
107
 
93
108
  ## Порядок
94
109
 
95
110
  1. Статья пишется в закон — без путей и имён файлов.
96
- 2. Правило объявляет закон в шапке и называет приём, которым статья исполняется.
97
- 3. Имена этого дерева и привязка каждой статьи уходят в `implementation.md` рядом; якорь
98
- проверяется открытием файла, а не памятью.
111
+ 2. Правило объявляет закон в шапке и называет то же самое в терминах этого дерева.
112
+ 3. Каждое утверждение правила получает строку в `implementation.md`; якорь проверяется
113
+ открытием файла, а не памятью.
99
114
  4. Готовый код уезжает в паттерн, а правило на него ссылается.
100
- 5. Проверка спеков — до пуша.
115
+ 5. `npm run check:specs` — до пуша.
101
116
 
102
117
  ## Частые промахи
103
118
 
104
- - Закон назвал файл проекта. Путям место в правиле, а точнее — в его компаньоне.
105
- - Компаньон лежит не рядом с правилом, а рядом с законом: он привязывает закон к этому проекту,
106
- и зелёная проверка это утвердит, потому что структура совпадёт с тем, чего проверка сама и
107
- ждёт.
108
- - Якорь ведёт в мёртвый символ: объявлен и больше нигде не встречается.
109
- - Статью переформулировали, а строку в привязке не тронули: связь идёт по тексту, и проверка
110
- перестанет её находить.
111
- - В описании не сказано, когда паттерн **не** брать, — соседний паттерн того же правила
119
+ - Закон назвал файл проекта проверка отбивает. Путям место в правиле.
120
+ - Спутник с привязкой лежит рядом с законом: он привязывает закон к этому проекту, а зелёная
121
+ проверка это утвердит, потому что структура совпадёт с тем, чего проверка сама и ждёт.
122
+ - Якорь ведёт в мёртвый символ: объявлен и больше нигде не встречается. Так пять правил про
123
+ правку сущности оказались привязаны к механике, которую не зовёт ни один экран.
124
+ - Утверждение переформулировали, а строку в привязке не тронули: связь идёт по тексту, и
125
+ проверка перестанет её находить.
126
+ - В `description` не сказано, когда паттерн **не** брать, — соседний паттерн того же правила
112
127
  становится неотличимым.