@rt-tools/agent-kit 0.2.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 (95) hide show
  1. package/README.md +59 -6
  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/patterns/angular-patterns-state.md +94 -0
  22. package/assets/patterns/api-layer-pair.md +78 -0
  23. package/assets/patterns/browser-verification-measure.md +83 -0
  24. package/assets/patterns/browser-verification-stand.md +79 -0
  25. package/assets/patterns/component-structure-new.md +98 -0
  26. package/assets/patterns/doc-style-sweep.md +100 -0
  27. package/assets/patterns/doc-style-write.md +106 -0
  28. package/assets/patterns/git-workflow-commit.md +175 -0
  29. package/assets/patterns/git-workflow-merge.md +82 -0
  30. package/assets/patterns/git-workflow-migration.md +58 -0
  31. package/assets/patterns/git-workflow-restart.md +49 -0
  32. package/assets/patterns/lib-layers-move.md +77 -0
  33. package/assets/patterns/lib-layers-new.md +70 -0
  34. package/assets/patterns/permissions-procedure.md +69 -0
  35. package/assets/patterns/platform-access-di.md +70 -0
  36. package/assets/patterns/reuse-first-extend.md +73 -0
  37. package/assets/patterns/seo-page.md +92 -0
  38. package/assets/patterns/seo-verify.md +64 -0
  39. package/assets/patterns/shared-code-new.md +80 -0
  40. package/assets/patterns/spec-driven-domain.md +100 -0
  41. package/assets/patterns/spec-driven-rule.md +112 -0
  42. package/assets/patterns/styling-bem-component.md +77 -0
  43. package/assets/patterns/styling-bem-layout.md +67 -0
  44. package/assets/patterns/testing-e2e.md +90 -0
  45. package/assets/patterns/testing-unit.md +93 -0
  46. package/assets/patterns/translations-key.md +51 -0
  47. package/assets/patterns/ts-procedure.md +66 -0
  48. package/assets/rules/angular-patterns.md +52 -0
  49. package/assets/rules/api-layer.md +53 -0
  50. package/assets/rules/browser-verification.md +69 -0
  51. package/assets/rules/component-structure.md +48 -0
  52. package/assets/rules/doc-style.md +61 -0
  53. package/assets/rules/git-workflow.md +106 -0
  54. package/assets/rules/lib-layers.md +54 -0
  55. package/assets/rules/permissions.md +52 -0
  56. package/assets/rules/platform-access.md +49 -0
  57. package/assets/rules/reuse-first.md +69 -0
  58. package/assets/rules/seo.md +50 -0
  59. package/assets/rules/shared-code.md +45 -0
  60. package/assets/rules/spec-driven.md +89 -0
  61. package/assets/rules/styling-bem.md +59 -0
  62. package/assets/rules/testing.md +69 -0
  63. package/assets/rules/translations.md +52 -0
  64. package/assets/rules/typescript-conventions.md +46 -0
  65. package/assets/templates/gate-map.sh +37 -0
  66. package/assets/templates/implementation.md +38 -0
  67. package/assets/templates/pattern.md +4 -0
  68. package/assets/templates/project.sh +41 -0
  69. package/assets/templates/rule.md +12 -23
  70. package/lib/assets.d.ts +8 -0
  71. package/lib/assets.d.ts.map +1 -1
  72. package/lib/assets.js +12 -1
  73. package/lib/assets.js.map +1 -1
  74. package/lib/commands.d.ts.map +1 -1
  75. package/lib/commands.js +21 -2
  76. package/lib/commands.js.map +1 -1
  77. package/lib/companion.d.ts +53 -0
  78. package/lib/companion.d.ts.map +1 -0
  79. package/lib/companion.js +33 -0
  80. package/lib/companion.js.map +1 -0
  81. package/lib/config.d.ts +24 -1
  82. package/lib/config.d.ts.map +1 -1
  83. package/lib/config.js +33 -1
  84. package/lib/config.js.map +1 -1
  85. package/lib/stamp.d.ts +2 -5
  86. package/lib/stamp.d.ts.map +1 -1
  87. package/lib/stamp.js +25 -10
  88. package/lib/stamp.js.map +1 -1
  89. package/lib/sync.d.ts +3 -0
  90. package/lib/sync.d.ts.map +1 -1
  91. package/lib/sync.js +20 -1
  92. package/lib/sync.js.map +1 -1
  93. package/package.json +1 -1
  94. package/rt-tools-agent-kit-0.3.0.tgz +0 -0
  95. package/rt-tools-agent-kit-0.2.0.tgz +0 -0
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: platform-access
3
+ kind: rule
4
+ law: frontend-application
5
+ description: Правило под закон «Фронтовое приложение». Брать, когда правка задевает глобальный объект или среду исполнения — окно, глобальную область, признак браузера, хранилище, наблюдатели. Глобальное приходит внедрением, среда проверяется службой, а не наличием глобала. Не действует на серверной стороне. Готовый код — в паттерне platform-access-di. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Окружение браузера — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/frontend-application.md`. Закон говорит, что должно быть верно;
11
+ здесь — каким приёмом прямое обращение к глобальному объекту заменяется. Какими токенами и
12
+ службами это названо и откуда они приходят — `implementation.md` рядом. Состояние —
13
+ `angular-patterns`, файл компонента — `component-structure`, оформление — `styling-bem`, слой
14
+ обращения к серверу — `api-layer`. Все пять под одним законом.
15
+
16
+ Правило про фронт: на серверной стороне своя среда, и ничего из перечисленного к ней не
17
+ относится.
18
+
19
+ ## Когда берётся
20
+
21
+ Правка задевает глобальный объект, признак среды, хранилище браузера или наблюдателя за
22
+ разметкой.
23
+
24
+ ## Что здесь действует
25
+
26
+ - **Глобальный объект приходит внедрением, а не берётся напрямую.** Тип уточняется приведением
27
+ к глобальной области: конструкторы наблюдателей объявлены на ней, а не на интерфейсе окна.
28
+ - **Среда проверяется службой, а не наличием глобала.** Проверка по наличию верна случайно и
29
+ ломается на первой же среде, где глобал подставлен.
30
+ - **Место прямого доступа заводится только с согласия владельца.** Их немного, и каждое
31
+ осознанно: скрипт, работающий до подъёма приложения, обработчик отказа подъёма и код,
32
+ исполняемый внутри страницы в сквозной спеке. Новое в этот список не добавляется молча.
33
+
34
+ ## Паттерны
35
+
36
+ - `platform-access-di` — готовые внедрения, приведение типа, чистые функции, проверка среды.
37
+
38
+ ## Ловушки
39
+
40
+ - **Фабрика токена окна бросает отказ, когда у документа нет представления.** Под отдачей
41
+ страницы сервером представление есть, и внедрение полем класса безопасно, но служба,
42
+ обязанная работать без разметки вовсе, берёт окно внутри метода под проверкой среды.
43
+ - **После правки, добавляющей окно в службу, которая создаётся на подъёме, нужна не только
44
+ сборка, но и поднятый сервер отдачи страниц.** Падение видно только там.
45
+ - **Вокруг хранилища проверка среды не нужна.** Служба хранилища и так уходит в память вне
46
+ браузера, и лишняя проверка вокруг чтения и записи — мёртвый код.
47
+ - **В чистых функциях внедрения нет** — окно принимается параметром, а внедряет его вызывающий.
48
+ - **Подготавливать состояние сквозной спеки записью в хранилище нельзя** — спека проходит те же
49
+ шаги, что и пользователь.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: reuse-first
3
+ kind: rule
4
+ law: reuse-first
5
+ description: Правило под закон «Единообразие приложения». Брать перед заведением любого нового экрана, компонента, поля, стора, сервиса, переводчика моделей или обработчика — на что опираться, по каким признакам видно, что готовое обошли. Что делать, когда готового не хватило, — в паттерне reuse-first-extend. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Единообразие — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/reuse-first.md`. Закон говорит, что одинаковые вещи ведут себя
11
+ одинаково; здесь — каким приёмом это держится. На какие именно источники вида и основы это
12
+ дерево опирается — `implementation.md` рядом.
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
+ вида или в базовом классе, и его видят остальные экраны. Клон, написанный рядом, забирает
41
+ правки на себя и расходится с оригиналом с первой же.
42
+
43
+ ## Паттерны
44
+
45
+ - `reuse-first-extend` — что делать, когда готового не хватило: расширить готовое, объявить
46
+ разовое отступление маркером, снять его.
47
+
48
+ ## Признаки, по которым видно, что готовое обошли
49
+
50
+ - в шаблоне фичи стоит нативный элемент ввода, кнопки, выбора, таблицы или диалога;
51
+ - отказ или предупреждение собраны руками — своя область оповещения вместо готового сообщения;
52
+ - в стилях фичи появились перекрытие всего экрана, своя вуаль, слой поверх всего, свои кадры
53
+ вращения или мерцания;
54
+ - в файле стилей экрана объявлена раскладка, а не только его собственные отличия;
55
+ - компонент сам реализует договор поля формы, вместо того чтобы наследовать основу;
56
+ - имя файла кончается на род готового компонента — кнопку, поле, диалог, таблицу — и лежит вне
57
+ источника вида;
58
+ - переводчик моделей переводит поля вручную, минуя общую основу;
59
+ - обработчик серверной стороны объявлен без общей метки.
60
+
61
+ ## Ловушки
62
+
63
+ - **Перенос переизобретением не считается.** Строка, которая уже лежала в дереве, при переезде
64
+ меняет отступ, оставаясь тем же кодом; сверка идёт без отступов, иначе каждый переезд читался
65
+ бы как новый код.
66
+ - **Ответ, данный до чтения образца, образец отменяет.** Согласованная форма переигрывается,
67
+ как только находится готовая: договорённость слабее того, что уже написано и работает.
68
+ - **Подсказка, зовущая за ненаписанным, останавливает работу.** Пока свой вариант не написан,
69
+ правило зовёт за готовым — а не за тем, что «должно появиться».
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: seo
3
+ kind: rule
4
+ law: search-visibility
5
+ description: Правило под закон «Видимость в поиске». Брать при любой правке, доходящей до разметки публичной части — шаблоны страниц, заголовок и описание, структурированные данные, канонический адрес, языковые ссылки, маршруты, карта сайта, правила обхода, конфиг прокси. Готовый код — в паттернах seo-page и seo-verify. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Видимость в поиске — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/search-visibility.md`. Закон говорит, что должно быть верно;
11
+ здесь — каким приёмом это держится. Какие локали набраны, где лежит служба тегов и чем зовётся
12
+ канонический путь — `implementation.md` рядом.
13
+
14
+ ## Когда берётся
15
+
16
+ Любая правка, доходящая до разметки публичной части: шаблон страницы, теги в голове документа,
17
+ структурированные данные, маршруты, карта сайта, правила обхода, конфиг прокси.
18
+
19
+ ## Что здесь действует
20
+
21
+ - **Свои теги помечены собственным атрибутом и при повторном применении переписываются.** Чужое
22
+ в голове документа не трогается: после оживления там остаются теги от отдачи сервером.
23
+ - **Канонический адрес ведёт на локализованный путь**, а не на корень и не на адрес локали по
24
+ умолчанию.
25
+ - **Языковые ссылки строятся по локалям, перевод которых готов**, плюс ссылка на локаль по
26
+ умолчанию. Полный список локалей для этого не годится: переводы содержимого заполняются
27
+ отдельно и готовы не всегда.
28
+ - **Список альтернативных локалей не включает локаль самой страницы** — иначе она объявлена и
29
+ основной, и альтернативной сразу.
30
+ - **Адрес в структурированных данных — канонический адрес самой страницы**, не корень.
31
+ - **Перенаправление с прежнего адреса отдаётся с временем жизни и кэшируется прокси.** Ключ
32
+ кэша строится без строки запроса, поэтому запросы с ней идут мимо кэша.
33
+
34
+ ## Паттерны
35
+
36
+ - `seo-page` — правка разметки страницы: теги, структурированные данные, новый маршрут, новая
37
+ страница в карте сайта.
38
+ - `seo-verify` — проверка отданной разметки на прод-сборке.
39
+
40
+ ## Ловушки
41
+
42
+ - **Тег, добавленный мимо общей службы, не помечен и потому не переписывается.** Он переживёт
43
+ переход между страницами и останется от чужой страницы.
44
+ - **Новый маршрут без ветки под каждую локаль существует только в локали по умолчанию.**
45
+ Остальные адреса отдадут отказ и поисковику, и читателю.
46
+ - **Новая страница не попадает в карту сайта сама** — карта строится из записей, а не из
47
+ маршрутов.
48
+ - **Адрес режется по первому знаку вопроса и только им.** Простой разрез по всем вхождениям
49
+ теряет всё после второго, и перенаправление приходит на страницу без разметки источника —
50
+ источник обращения считается неверно.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: shared-code
3
+ kind: rule
4
+ law: shared-code
5
+ description: Правило под закон «Общий код приложений». Брать, когда значение должно одинаково пониматься всеми приложениями — предел выборки, набор операторов условия, направление порядка, длина поля, форма запроса и ответа списка. Откуда берётся общее, что считается копией и что ловит проверка повторов. Готовый код — в паттерне shared-code-new. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Общий код — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/shared-code.md`. Закон говорит, что общим быть обязано; здесь —
11
+ каким приёмом это держится. Из какого пакета и какой либы что берётся — `implementation.md`
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
+ - `shared-code-new` — как завести новое общее число, функцию или тип и не оставить копию.
37
+
38
+ ## Ловушки
39
+
40
+ - **Помощник приведения типов для сверки с набором не годится.** Значение вне набора он пишет в
41
+ журнал и возвращает строкой, то есть глотает ровно тот случай, ради которого сверку и завели.
42
+ - **Накопленные повторы лежат в списке исключений и отказом не считаются.** Гейт падает только
43
+ на новом; список исключений только сокращается.
44
+ - **Проверка не ловит ту же логику, написанную заново под другим именем.** Совпадение она ищет
45
+ по тексту, а не по смыслу.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: spec-driven
3
+ kind: rule
4
+ law: project-documentation
5
+ description: Правило под закон «Документация проекта». Брать при правке спека домена, закона и любого скила. Три слоя — закон, правило, паттерн, — обязательные разделы, привязка утверждений к коду, связь сценариев с тестами. Готовый порядок действий — в паттернах spec-driven-domain и spec-driven-rule. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Документация проекта — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/project-documentation.md`. Закон говорит, что должно быть верно
11
+ про тексты; здесь — из каких слоёв они сложены и что сверяет машина. Где лежат спеки домена,
12
+ чем они проверяются и какой у них шаблон — `implementation.md` рядом. Формулировки — правило
13
+ `doc-style` под тем же законом.
14
+
15
+ ## Когда берётся
16
+
17
+ Правка закона, правила, паттерна или спека домена. Заведение нового слоя документации.
18
+
19
+ ## Как сложены слои
20
+
21
+ ```
22
+ ЗАКОН {{lawsDir}}/<закон>.md
23
+ верен для любого приложения этого класса; о проекте не знает ничего:
24
+ ни путей, ни имён файлов, ни привязок
25
+
26
+ ├─ ПРАВИЛО {{rulesDir}}/<правило>/SKILL.md (kind: rule, law: <закон>)
27
+ │ каким приёмом закон исполняется; несколько правил на закон
28
+ │ {{rulesDir}}/<правило>/implementation.md — имена этого дерева и привязка к коду
29
+
30
+ │ └─ ПАТТЕРН {{rulesDir}}/<правило>-<что>/SKILL.md (kind: pattern, rule: <правило>)
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
+ - `spec-driven-domain` — заведение и правка спека домена, сценарии, привязка.
66
+ - `spec-driven-rule` — заведение закона, правила и паттерна.
67
+
68
+ ## Ловушки
69
+
70
+ - **Список шагов в спеке не заводить.** Шаги — артефакт сессии, им место в ветке или в описании
71
+ PR. Как только в директории появляются «шаги», спек снова становится планом и умирает после
72
+ слияния.
73
+ - **Спек описывает установившееся, а не предстоящее.** Единственное место, где он говорит о
74
+ будущем, — отдельная директория предложенного; после выкатки её текст вливается в спек
75
+ домена, директория удаляется, идентификаторы сценариев не меняются.
76
+ - **Семантику полей не сверяет ничто.** Проверка знает имена обработчиков, коды отказа и связь
77
+ сценариев с тестами; что означает пустое поле — не знает.
78
+ - **Живость символа считается совпадением имени по дереву, а не вызовом.** Символу хватает
79
+ второго упоминания где угодно — в чужом поле с тем же именем, в атрибуте разметки. Место, где
80
+ правило исполняется на самом деле, подтверждается только чтением кода.
81
+ - **Зелёная проверка не значит, что структура верна.** Проверка сверяет структуру с тем, чего
82
+ сама и ждёт: неверная раскладка, совпавшая с её ожиданием, проходит зелёной.
83
+ - **Конфликт слияния в спеке разрешается сохранением обеих сторон, а не выбором одной.** Две
84
+ ветки дописывают в конец одних и тех же списков, и обе стороны верны: конфликт здесь не спор,
85
+ а две дописи в одно место. Номера сценариев при разрешении не пересчитываются — идентификатор
86
+ это ключ связи с тестами, и сдвиг номеров рвёт сверку у соседей, которых правка не касалась.
87
+ Порядок сохранённых сторон держится одинаковым во всех файлах спека, иначе правило, его
88
+ сценарий и его привязка перестают находиться друг по другу. После разрешения гоняется
89
+ проверка спеков: конфликт в тексте кода не задевает, и ни сборка, ни линтеры его не увидят.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: styling-bem
3
+ kind: rule
4
+ law: frontend-application
5
+ description: Правило под закон «Фронтовое приложение». Брать при правке любого файла стилей и шаблона компонента — токены оформления вместо сырых значений, класс директивой, общий слой раскладки, класс без правила. Готовый код — в паттернах styling-bem-layout и styling-bem-component. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Оформление — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/frontend-application.md`. Закон говорит, что должно быть верно;
11
+ здесь — каким приёмом это держится. Как названы токены, директивы классов и общий слой
12
+ раскладки — `implementation.md` рядом. Раскладка файла компонента — `component-structure`,
13
+ состояние — `angular-patterns`, окружение браузера — `platform-access`, слой обращения к
14
+ серверу — `api-layer`. Все пять под одним законом.
15
+
16
+ ## Когда берётся
17
+
18
+ Правка любого файла стилей и любого шаблона компонента. И раньше всего этого — момент, когда
19
+ рука тянется написать шестнадцатеричный цвет или число на месте.
20
+
21
+ ## Что здесь действует
22
+
23
+ - **Оформление берётся токеном, а не пишется значением на месте.** Составные значения — тени,
24
+ обводки — берутся готовым токеном целиком, а не собираются из частей: собранное из частей
25
+ расходится с оригиналом при первой правке шкалы.
26
+ - **У каждого класса элемента есть своё правило стилей.** Класс без правила выглядит рабочим и
27
+ молча ничего не делает.
28
+ - **Класс ставится директивой, а не строкой в атрибуте.** Имя блока элемент получает от
29
+ ближайшего предка, объявившего блок, и повторить этот разбор по тексту шаблона нечем.
30
+ - **Раскладка объявлена в общем слое приложения, а не в стилях экрана.** У компонента экрана
31
+ файл стилей по умолчанию пустой.
32
+ - **Предупреждение линтера стилей роняет прогон наравне с ошибкой.** Иначе запрет читается как
33
+ пожелание: нарушения лежат в дереве, а прогон возвращает успех и гейтом не является.
34
+
35
+ ## Паттерны
36
+
37
+ - `styling-bem-layout` — экран на общем слое раскладки, блоки приложения.
38
+ - `styling-bem-component` — стили компонента источника вида, хост, модификаторы.
39
+
40
+ ## Ловушки
41
+
42
+ - **Директива элемента без предка, объявившего блок, роняет отрисовку во время работы** —
43
+ сборка и линтер при этом молчат.
44
+ - **Директива блока на контейнере без своего узла класса не ставит вовсе:** такой узел это
45
+ комментарий, и имя блока он только объявляет потомкам. Класс блока экрана вешает хост.
46
+ - **Выравнивание по центру в прокручиваемой ленте уводит первые элементы за нулевой скролл** —
47
+ доскроллить до них невозможно. В прокручиваемых лентах берётся безопасный вариант
48
+ выравнивания.
49
+ - **Резерв под полосу прокрутки на корне сужает содержащий блок для закреплённых элементов.**
50
+ Попап, выровненный по правому краю, встаёт на ширину резерва левее своей кнопки.
51
+ - **Изнутри компонента до соседнего хоста не дотянуться.** Разделитель между повторяющимися
52
+ хостами объявляется через отрицание первого, а не соседним селектором.
53
+ - **Атрибут доступности визуального состояния не даёт.** Браузер стилизует собственное
54
+ состояние элемента, а атрибуты доступности — нет: к каждому такому атрибуту заводится своё
55
+ правило.
56
+ - **Гарнитуру с корня элементы формы не наследуют** — браузер задаёт им свой шрифт.
57
+ Наследование включается глобально и не сбрасывается.
58
+ - **Комментарии-выключатели линтера стилей не ставятся.** Селекторы объединяются вложенностью.
59
+ - **При переносе стилей новых объявлений не появляется** — только перемещение существующих.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: testing
3
+ kind: rule
4
+ law: verifiability
5
+ description: Правило под закон «Проверяемость». Брать при правке любого файла спеки и всего, что лежит в сквозных прогонах. Идентификатор сценария в заголовке теста, отметка непокрытого, вынос решения в чистую функцию, выключатели разрушающих спек. Готовый код — в паттернах testing-unit и testing-e2e. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Проверяемость — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/verifiability.md`. Закон говорит, что считается подтверждением;
11
+ здесь — каким приёмом это делается. Чем это названо в этом дереве, каким прогонщиком гоняется и
12
+ где лежит — `implementation.md` рядом. Проверка работающего приложения глазами и замером —
13
+ правило `browser-verification` под тем же законом.
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
+ приложении.
41
+ - **Правило линтера, которое запрещает принятый здесь приём, выключают в конфиге, а не обходят
42
+ в каждом тесте.** Точечное отключение в файле остаётся для того, что запрещено по делу; рядом
43
+ со строкой отключения пишут причину.
44
+
45
+ ## Паттерны
46
+
47
+ - `testing-unit` — тест на чистую функцию, на обработчик серверной стороны и разовый
48
+ тест-доказательство, который не коммитится.
49
+ - `testing-e2e` — прогон сквозных тестов, стенд под настоящим прокси, выключатели.
50
+
51
+ ## Ловушки
52
+
53
+ - **Зелёный прогон тестов не значит, что хоть один файл исполнялся.** Либа без своего конфига
54
+ прогонщика не запускает ничего. Либа с конфигом, но без единого файла спеки, проходит зелёной
55
+ из-за настройки «успех при отсутствии тестов», и на глаз эти два случая неотличимы: в обоих
56
+ прогон успешен. Перед правкой в незнакомой либе проверяется, есть ли в ней хоть один файл
57
+ спеки; если нет — первый заводится этой же правкой, а не откладывается: откладывать здесь не
58
+ с чего, долг уже накоплен.
59
+ - **«Executable doesn't exist» — состояние машины, а не дефект правки.** Обычно установлен один
60
+ движок браузера, остальные падают всегда. Та же ошибка приходит после смены версии
61
+ прогонщика сквозных тестов: браузер ставится под конкретную версию, и после подъёма его надо
62
+ поставить заново. Выглядит это как регрессия обновления, а ею не является.
63
+ - **Первому прогону сразу после установки браузера верить нельзя.** Падения, не повторяющиеся
64
+ ни при отдельном прогоне тех же тестов, ни при втором полном, — свойство первого прогона.
65
+ Такой прогон повторяют, а выводы делают по второму.
66
+ - **Сквозные тесты без учётных данных в окружении пропускаются молча.** В отчёте они значатся
67
+ пропущенными, и прогон выглядит успешным.
68
+ - **Поднятый сервер разработки проверкой не является.** Это шаг правила `browser-verification`,
69
+ а не тест.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: translations
3
+ kind: rule
4
+ law: locales
5
+ description: Правило под закон «Локали и переводы». Брать при заведении любого видимого текста, правке словарей, префиксов локалей в адресе и перевода содержимого записи. Текст из словаря во всех локалях, пустой перевод как пропуск, производные переводы содержимого, начальная валюта локали. Готовый код — в паттерне translations-key. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Локали и переводы — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/locales.md`. Закон говорит, что должно быть верно; здесь — каким
11
+ приёмом это держится. Какие именно локали набраны, чем зовётся библиотека переводов и где лежат
12
+ словари — `implementation.md` рядом.
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
+ - `translations-key` — заведение ключа во всех локалях и подстановка в разметку.
40
+
41
+ ## Ловушки
42
+
43
+ - **Полноту словарей держит не работающее приложение, а тест.** Он роняет прогон на
44
+ недостающем или пустом ключе; без него дыра видна только на экране.
45
+ - **Наборы ключей сверяются внутри раздела**, а не по всему словарю сразу: словари разложены на
46
+ общий, публичную часть, письма и внутреннюю часть.
47
+ - **Перевод содержимого идёт до записи, а не после.** Иначе страница оказывается наполовину
48
+ переведённой; кэш сбрасывается после записи и один раз.
49
+ - **Без ключа доступа к переводчику сохранение проходит**, но переводы остаются прежними — и
50
+ единственный признак этого владелец видит предупреждением.
51
+ - **Новый маршрут без ветки под каждую локаль существует только в локали по умолчанию.**
52
+ Остальные адреса отдадут отказ и поисковику, и читателю.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: typescript-conventions
3
+ kind: rule
4
+ law: code-structure
5
+ description: Правило под закон «Устройство кода». Брать при правке любого .ts, кроме тех, у которых есть своё правило, — род объявления в имени, модификаторы доступа, приватные поля, суффикс источника, запрет приведения в переводчике моделей. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Устройство кода — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/code-structure.md`. Закон говорит, что должно быть верно про
11
+ объявления; здесь — как это записывается. Какими правилами линтера это держится и где они
12
+ лежат — `implementation.md` рядом.
13
+
14
+ ## Когда берётся
15
+
16
+ Правка любого файла с кодом, у которого нет своего правила: функции, типа, перечисления,
17
+ переводчика моделей, обработчика серверной стороны.
18
+
19
+ ## Что здесь действует
20
+
21
+ - **Род объявления виден по префиксу имени, и это держат правила линтера.** У интерфейса, у
22
+ типа и у перечисления свои; проверяются все файлы с кодом, а не выборочно.
23
+ - **Источник, за которым следят, назван суффиксом.** Пишущий источник и наблюдаемое, поднятое
24
+ из него, различаются в месте использования, а не переходом к объявлению.
25
+ - **Тип берётся из того пакета, где объявлен.** Своя копия чужого типа расходится с оригиналом
26
+ молча, а компилируется из них только одна.
27
+ - **Отметка об устаревании ставится вместе с обходом потребителей.** Пометка на типе красит
28
+ каждое место, где его ещё зовут: один `@deprecated` на файл даёт замечания во всех чужих
29
+ доменах разом, и правка перестаёт быть локальной.
30
+ - **Приведение значения к типу в переводчике моделей не пишется.** Оно принимает любое значение
31
+ и компилируется — то есть снимает ровно ту проверку, ради которой переводчик и заведён.
32
+
33
+ ## Паттерны
34
+
35
+ - `ts-procedure` — завести обработчик серверной стороны: класс, метка, право, регистрация.
36
+
37
+ ## Ловушки
38
+
39
+ - **Неиспользуемый параметр убирается, а не переименовывается.** Подчёркивание перед именем
40
+ прячет замечание, но параметр остаётся в сигнатуре и продолжает обещать значение.
41
+ - **Агрегат хранилища своим сгенерированным типом не аннотируется.** Сгенерированный тип шире,
42
+ чем результат выборки, и аннотация врёт — причём в сторону, которую компилятор не оспорит.
43
+ - **Своё правило линтера включается вместе с переводом всех, кого оно ловит.** Включённое
44
+ поверх накопленного даёт красный прогон на файлах, которых правка не касалась.
45
+ - **Приватное поле с решёткой видно только внутри класса.** Там, где к полю обращается шаблон
46
+ или обёртка каркаса, оно объявляется защищённым, а не приватным.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env bash
2
+ # Карта «что правится — какое правило» этого дерева. Её читает хук гейта правил.
3
+ #
4
+ # Живёт в проекте, а не в пакете: имена каталогов, расширения и команды поставки у каждого
5
+ # дерева свои. Пакет везёт механизм, проект — карту.
6
+ #
7
+ # Функция печатает ИМЯ ПРАВИЛА или молчит. Молчание — «правила на это нет», и гейт пропускает.
8
+ #
9
+ # Порядок веток решает: первое совпадение выигрывает, поэтому частное идёт раньше общего.
10
+ # Файл спеки — не файл компонента, и обе ветки обязаны стоять до общей ветки расширения.
11
+
12
+ skill_for() {
13
+ kind="$1"
14
+ target="$2"
15
+
16
+ case "$kind" in
17
+ edit)
18
+ case "$target" in
19
+ # Файлы самого агента правятся без правила: правило на них — это оно само.
20
+ */.claude/*) return 0 ;;
21
+ *.spec.ts) printf '%s' '<правило про тесты>' ;;
22
+ *.component.ts|*.component.html) printf '%s' '<правило про компонент>' ;;
23
+ *.scss) printf '%s' '<правило про оформление>' ;;
24
+ */index.ts) printf '%s' '<правило про раскладку либ>' ;;
25
+ *.ts) printf '%s' '<правило про код>' ;;
26
+ *.md) printf '%s' '<правило про тексты>' ;;
27
+ esac
28
+ ;;
29
+ bash)
30
+ case "$target" in
31
+ *git\ commit*|*git\ push*|*gh\ pr\ create*) printf '%s' '<правило про поставку>' ;;
32
+ esac
33
+ ;;
34
+ esac
35
+
36
+ return 0
37
+ }