@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,66 @@
1
+ ---
2
+ name: ts-procedure
3
+ kind: pattern
4
+ rule: typescript-conventions
5
+ description: Паттерн правила typescript-conventions. Брать при заведении или правке обработчика серверной стороны — класс с полем метода контракта и методом обработки, зависимости конструктором, имя файла и класса, почему форма именно такая. Не брать для объявления доступа — это паттерн permissions-procedure.
6
+ ---
7
+
8
+ # Обработчик серверной стороны
9
+
10
+ Паттерн правила `typescript-conventions`. Что при этом должно быть верно — закон
11
+ `{{lawsDir}}/code-structure.md`.
12
+
13
+ ## Когда брать
14
+
15
+ - Заводится новый обработчик серверной стороны.
16
+ - Правится тело существующего.
17
+ - Домен переезжает на вертикальную нарезку.
18
+
19
+ ## Один обработчик — один класс
20
+
21
+ Файл рядом со своим доменом, класс с публичным полем метода контракта и публичным методом
22
+ обработки. Зависимости приходят конструктором: на серверной стороне внедрение конструкторное, и
23
+ функции внедрения фронта там нет.
24
+
25
+ ```typescript
26
+ @Injectable()
27
+ @ConnectProcedure()
28
+ @RequiresPermission('<ресурс>:<действие>')
29
+ export class PingProcedure implements IConnectProcedure<typeof HealthService.method.ping> {
30
+ readonly #health: HealthCheckService;
31
+
32
+ public readonly method: typeof HealthService.method.ping = HealthService.method.ping;
33
+
34
+ constructor(health: HealthCheckService) {
35
+ this.#health = health;
36
+ }
37
+
38
+ public async handle(): Promise<{ status: EHealthStatus }> {
39
+ return { status: (await this.#health.check()).status };
40
+ }
41
+ }
42
+ ```
43
+
44
+ Объявление доступа обязательно, и оно ровно одно — паттерн `permissions-procedure`.
45
+
46
+ ## Почему форма такая
47
+
48
+ Прежняя — регистрация с телами в замыканиях внутри вызова роутера — делала обработчик
49
+ недостижимым для спеки: наружу торчал только метод регистрации. А регистрация сервиса целиком
50
+ заглушает каждый непереданный метод ответом «не реализовано», поэтому один сервис контракта не
51
+ мог обслуживаться двумя доменами.
52
+
53
+ Класс решает и то, и другое: метод обработки зовётся спекой напрямую, а реестр кладёт
54
+ обработчики поштучно.
55
+
56
+ ## Частые промахи
57
+
58
+ - **Третий суффикс имени файла:** прежние имена уходят вместе с последним переехавшим доменом,
59
+ и новых таких файлов не заводится.
60
+ - **Функция внедрения фронта в классе обработчика:** зависимости идут конструктором.
61
+ - **Тело в замыкании внутри регистрации:** спека до него не дотянется.
62
+ - **Обработчик без объявления доступа:** приложение не поднимется.
63
+ - **Приведение к типу в переводе моделей:** на серверной стороне оно запрещено так же, как во
64
+ фронтовом переводчике.
65
+ - **Свой тип у результата группирующей выборки:** он условный, собирается из аргументов вызова
66
+ и с выписанным руками не сходится.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: angular-patterns
3
+ kind: rule
4
+ law: frontend-application
5
+ description: Правило под закон «Фронтовое приложение». Брать при правке любого класса фронтового каркаса — компонента, стора, сервиса, директивы, преобразователя, стража, перехватчика. Реактивное состояние вместо ручного пересчёта, перерисовка по требованию, место подписки и её владелец. Не действует на серверной стороне. Готовый код — в паттерне angular-patterns-state. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Реактивность экрана — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/frontend-application.md`. Закон говорит, что должно быть верно;
11
+ здесь — каким приёмом это держится. Чем названы реактивное значение, входы и выходы и как
12
+ зовётся гашение подписки — `implementation.md` рядом. Раскладка файла компонента —
13
+ `component-structure`, оформление — `styling-bem`, окружение браузера — `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
+
38
+ - `angular-patterns-state` — реактивные значения, производные, состояние сервиса, подписка.
39
+
40
+ ## Ловушки
41
+
42
+ - **Производное значение объявляется вычисляемым, а не эффектом.** Эффект, кладущий значение в
43
+ реактивное поле, — это ручной пересчёт, и он рано или поздно отстаёт от источника.
44
+ - **Геттеров в компонентах нет.** Геттер пересчитывается на каждой перерисовке, и цена его не
45
+ видна ни в одном месте кода.
46
+ - **Подписка на каждый вызов метода не даёт выбрать, что делать с предыдущим запросом.**
47
+ Быстрые нажатия дают гонку ответов, и побеждает тот, что вернулся последним, а не тот, что
48
+ нажали последним.
49
+ - **Запрет подписки в методе идёт по имени, а не по типу.** Вызов с таким именем у чего угодно
50
+ считается подпиской, а взятие метода без вызова — нет.
51
+ - **Инициализация разметки после первой отрисовки делается своим крючком, а не крючком
52
+ жизненного цикла представления.** Когда страницу отдаёт сервер, разметка появляется позже.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: api-layer
3
+ kind: rule
4
+ law: frontend-application
5
+ description: Правило под закон «Фронтовое приложение». Брать при правке слоя обращения к серверу во фронтовом домене — пары «фасад и служба» и переводчиков моделей при ней. Один вход выборки у списка, общий конвертер страницы, поток вместо ожидания. Готовый код — в паттерне api-layer-pair. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Обращение к серверу — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/frontend-application.md`. Закон говорит, что должно быть верно;
11
+ здесь — из чего сложен слой обращения к серверу. Как названы модели выборки, где лежат
12
+ переводчики и чем зовётся общий конвертер — `implementation.md` рядом. Состояние —
13
+ `angular-patterns`, файл компонента — `component-structure`, оформление — `styling-bem`,
14
+ окружение браузера — `platform-access`. Все пять под одним законом.
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
+ - `api-layer-pair` — готовые фасад, служба и перевод выборки.
42
+
43
+ ## Ловушки
44
+
45
+ - **Выборка в ответе — применённая, а не запрошенная.** Порядок по умолчанию и отброшенное
46
+ сервером условие экран иначе не увидит.
47
+ - **Одна пара — одна сущность.** У связанных сущностей свои пары, даже когда их обработчики
48
+ лежат в одном сервисе контракта.
49
+ - **Метод, которого у домена нет, не объявляется.** Список читают все, правят не все.
50
+ - **Серверный поток событий — исключение из правила про поток.** Живой срез приходит
51
+ асинхронным итератором, и заворачивать его некуда.
52
+ - **Своей копии общих переводчиков страницы, порядка и отбора домен не заводит.** Второй
53
+ экземпляр ловит проверка повторов — правило `shared-code`.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: browser-verification
3
+ kind: rule
4
+ law: verifiability
5
+ description: Правило под закон «Проверяемость». Брать при любой проверке через браузер и при запросах к поднятому приложению из командной строки. Чему на сервере разработки верить нельзя, чем измерять вместо взгляда, почему браузер водится одним драйвером. Готовый код — в паттернах browser-verification-stand и browser-verification-measure. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Проверка работающего приложения — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/verifiability.md`. Закон говорит, что считается подтверждением;
11
+ здесь — каким приёмом приложение проверяется живьём. На каких портах оно поднято, каким
12
+ драйвером водится браузер и где лежит конфиг прокси — `implementation.md` рядом. Тесты под тем
13
+ же законом — правило `testing`.
14
+
15
+ ## Когда берётся
16
+
17
+ Любая проверка через браузер, любой запрос к поднятому приложению из командной строки, любой
18
+ вывод о вёрстке.
19
+
20
+ ## Что здесь действует
21
+
22
+ - **Свой сервер разработки не поднимается.** Приложения уже подняты владельцем; второй
23
+ экземпляр слушает другой порт и отвечает другой сборкой, а расхождение читается как дефект
24
+ правки.
25
+ - **Браузер водится одним драйвером на закреплённом профиле.** Остальные двери — второй
26
+ драйвер, открытие ссылки средствами системы, запуск бинарника — закреплённый профиль не
27
+ спрашивают вовсе и приходят в сеанс без входа.
28
+ - **Выбор браузера протухает и требует повторного вызова.** Выбор, сделанный в начале сессии,
29
+ не держится: после паузы следующий вызов открывает вкладку в другом профиле молча.
30
+ - **Профиль не выбирается из списка и не спрашивается у владельца.** Список отдаёт неустойчивые
31
+ имена, которые не опознают ничего, а выбор из него ведёт на профиль без входа.
32
+ - **Прод-конфигурация проверяется только за настоящим прокси.** Голый сервер отдачи страниц про
33
+ кэш, перенаправления и заголовки не знает ничего.
34
+ - **Вывод о вёрстке подкрепляется числом.** «Выглядит нормально» результатом проверки не
35
+ является; чем мерить — паттерн `browser-verification-measure`.
36
+
37
+ ## Паттерны
38
+
39
+ - `browser-verification-stand` — честный стенд из прод-сборки, вход в приложение, разбор порта.
40
+ - `browser-verification-measure` — замер вместо взгляда, ловушки инструмента снимка экрана.
41
+
42
+ ## Ловушки
43
+
44
+ - **Сначала выяснить, что отвечает на порту.** На порту регулярно висит собранный артефакт из
45
+ прошлой сессии: он отвечает успехом на старом коде, а заведённого в ветке обработчика у него
46
+ нет вовсе — и отказ читается как дефект регистрации. Таких процессов бывает несколько, и
47
+ завершение по имени команды не попадает ни в один: убивать по идентификатору процесса,
48
+ каждый.
49
+ - **Инкрементальная сборка протухает поштучно.** Разметка бывает уже новой, а клиентский кусок
50
+ — от компиляции до правки. Признак сборки для разработки — имена файлов сборки без хеша.
51
+ Расхождение между ответом из командной строки и страницей после оживления — повод пересобрать,
52
+ а не искать дефект в коде; вывод «такого маршрута нет» отсюда тоже не следует.
53
+ - **Кэш объясняет расхождение, но не подтверждает его.** Вывод «дефекта нет, это кэш» закрывает
54
+ разбор, поэтому принимается только после проверки на чистой сборке.
55
+ - **Сообщение об отсутствии отладочных API каркаса принадлежит расширению браузера, а не
56
+ приложению.** Прод-сборка их не публикует, и лечить это правкой кода не надо: опубликованные,
57
+ они дают карту внутренностей любому, кто откроет консоль.
58
+ - **Поведение маршрутизации воспроизводится нажатиями.** Подстановка адреса и заход по прямой
59
+ ссылке поднимают приложение заново, и накопленного состояния у него нет.
60
+ - **Замер отвечает только на заданный вопрос.** Отступы, кегль и скругление сходятся с
61
+ образцом, пока никто не спросил про фон на наведении, — а держится расхождение при верных
62
+ числах ровно столько, сколько его не спрашивают.
63
+ - **Если сменилась версия пакета, который рисует вёрстку, экраны обходят руками.** Тесты
64
+ нажимают по меткам и остаются зелёными, даже когда отступ съехал, размер пропал, а строка
65
+ стала другой высоты: они проверяют переходы, а не вид. Пары снимков тут тоже мало — смотрят
66
+ по очереди все экраны, которые этот пакет рисует.
67
+ - **Путей запуска несколько, и проверять их надо порознь.** Локальная команда, образ и состав
68
+ прода — разные пути; переменная, заданная в команде проверки, не говорит про образ ничего.
69
+ Пути перечисляются до проверки, а не после того, как один из них сошёлся.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: component-structure
3
+ kind: rule
4
+ law: frontend-application
5
+ description: Правило под закон «Фронтовое приложение». Брать при правке любого файла компонента и его шаблона — порядок свойств декоратора, группировка импортов, договорённости шаблона, обязательный якорь для спек, класс блока на хосте. Готовый код — в паттерне component-structure-new. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Файл компонента — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/frontend-application.md`. Закон говорит, что должно быть верно;
11
+ здесь — как устроен сам файл компонента и его шаблон. Какой у компонентов префикс, чем зовётся
12
+ якорь спек и где лежат правила линтера — `implementation.md` рядом. Состояние и потоки —
13
+ `angular-patterns`, оформление — `styling-bem`, окружение браузера — `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
+ - `component-structure-new` — готовый файл компонента и договорённости шаблона.
36
+
37
+ ## Ловушки
38
+
39
+ - **Ссылка на фрагмент в разметке не прокручивает страницу.** Когда в разметке объявлен
40
+ базовый адрес, браузер разрешает фрагмент относительно него: вместо прокрутки получается
41
+ полная навигация с перезагрузкой. Прокрутка делается средствами маршрутизатора.
42
+ - **Один и тот же компонент в обеих ветках условия — это условная привязка.** Две ветки с
43
+ разными входами пересоздают компонент и теряют его состояние.
44
+ - **Компонент, который рисуется в перекрытии, из хоста вызывающего не адресуется.** Его
45
+ разметка лежит вне хоста, и селектор от хоста до его кнопок не дотянется: такие кнопки носят
46
+ собственные якоря в своём шаблоне.
47
+ - **Готовое не пишется заново.** Своя разметка с ролью оповещения, таблицы, диалога, вкладок
48
+ или подсказки означает, что мимо готового компонента прошли. Правило целиком — `reuse-first`.
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: doc-style
3
+ kind: rule
4
+ law: project-documentation
5
+ description: Правило под закон «Документация проекта». Брать при правке любого документа, включая спеки, а также комментариев в коде, тел коммитов и описаний PR. Пути, которые существуют, пара «правка и её документ», словарь проекта, запрет упоминать чужие проекты. Готовые формулировки — в паттерне doc-style-write. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Тексты проекта — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/project-documentation.md`. Закон говорит, что должно быть верно
11
+ про тексты; здесь — каким приёмом это держится и что остаётся за автором. Где лежит словарь,
12
+ чем проверяются пути и какие пары требует гейт — `implementation.md` рядом. Устройство спеков и
13
+ слоёв документации — правило `spec-driven` под тем же законом.
14
+
15
+ ## Когда берётся
16
+
17
+ Правка любого документа, комментария в коде, тела коммита, описания PR.
18
+
19
+ ## Что здесь действует
20
+
21
+ - **Путь, названный в документе, существует.** Ссылка на переехавший файл читается как
22
+ действующее указание, и следующий читатель заводит снятое заново.
23
+ - **Описание прошлого из проверки путей выведено целиком.** Архив по устройству называет файлы,
24
+ которых уже нет, и правкой это не лечится.
25
+ - **Документ едет в том же коммите, что и правка, которую он описывает.** Обход — отметка с
26
+ причиной в теле коммита; пустая причина не принимается.
27
+ - **Термин берётся из словаря проекта, а не придумывается на месте.** Слова, которого там нет,
28
+ у читателя нет тоже. Новое слово либо заводится в словаре вместе с правкой, либо заменяется
29
+ тем, что уже есть.
30
+ - **Чужие проекты не упоминаются нигде** — ни имени репозитория, ни «портировано из», ни ссылок
31
+ на его файлы. Описывается то, что код делает здесь, в терминах этого проекта.
32
+
33
+ ## Паттерны
34
+
35
+ - `doc-style-write` — как формулировать: примеры «так» и «не так», правила для комментариев.
36
+ - `doc-style-sweep` — разбор документа, накопившего список работ, на действующее и закрытое.
37
+
38
+ ## Ловушки
39
+
40
+ - **Оставшаяся работа не записывается в документ, а заводится задачей.** «Сделать потом» в
41
+ плане, README или спеке — второй список работ: он расходится с очередью задач молча, а
42
+ разбирать его потом дороже, чем завести задачу сразу. Документ держит только то, что задачей
43
+ не бывает: договорённости и решения, которые решено не править.
44
+ - **Словарь действует и на разговор с владельцем, не только на файлы.** Слово, от которого в
45
+ дереве отказались, всплывает именно в отчёте о сделанном — и владелец читает ровно то слово,
46
+ которое просил не употреблять.
47
+ - **Проход по словарю глазами слово не находит.** «Формулировки приведены к словарю» означает
48
+ ровно те строки, которые в тот момент читали. Снятое слово вычищается поиском по всему дереву,
49
+ а не вычиткой; ищутся сочетания, а не корень — совпадений по корню законных обычно больше,
50
+ чем нарушений.
51
+ - **Снятое имя вычищается одним проходом по всему дереву:** правила, их зеркала, документы и
52
+ комментарии. Описание того, чего в коде уже нет, читается как действующее указание.
53
+ - **Число в тексте пересчитывается командой в том же коммите, где пишется.** Оно стареет внутри
54
+ одной ветки. Число, которое придётся пересчитывать при каждой правке, лучше не писать вовсе;
55
+ число, полученное разбором текста, сверяется на выборке руками — разбор, не знающий второй
56
+ формы записи, ошибается молча.
57
+ - **Сделанность читается по дереву, а не по тексту, который о ней написан.** Это верно в обе
58
+ стороны: вычеркнутый пункт при несделанной работе и несделанным названная задача, закрытая
59
+ наполовину, встречаются одинаково часто. Пункт плана описывает день, когда его написали.
60
+ - **Комментарий в файле — такое же утверждение, как строка в документе.** Выдуманное
61
+ обоснование живёт в коде годами и каждый раз читается как основание ничего не трогать.
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: git-workflow
3
+ kind: rule
4
+ law: delivery
5
+ description: Правило под закон «Поставка». Брать на заведение задачи, ветки, коммит, пуш, создание PR, слияние, а также на правку схемы хранилища и её миграций. Задача как начало работы, колонка задачи как ход работы, соответствие задачи и ветки один к одному, формат коммита, обязательный состав PR, сторожевые хуки. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration и git-workflow-restart. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Поставка — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/delivery.md`. Закон говорит, что должно быть верно; здесь — каким
11
+ приёмом это держится. Как названы главная ветка, борда, колонки, формат имени ветки и учётная
12
+ запись машинной работы — `implementation.md` рядом.
13
+
14
+ ## Когда берётся
15
+
16
+ Заведение задачи и ветки, коммит, пуш, открытие PR, слияние, правка схемы хранилища и её
17
+ миграций, ручной перезапуск прода.
18
+
19
+ ## Что здесь действует
20
+
21
+ - **Коммит в главную ветку отбивается гардом.** Гард ищет вызов коммита в любом месте команды и
22
+ смотрит текущую ветку на момент запуска, поэтому составная «создать ветку и сразу коммитить»
23
+ отклоняется целиком: ветки в момент разбора ещё нет.
24
+ - **Ветка без номера задачи PR не открывает.** Локально такая ветка законна, но правка из неё —
25
+ это выкатка, за которой в очереди работ ничего не стоит.
26
+ - **Номер ветки и номер в заголовке PR сверяются на месте, а состояние задачи — по борде.**
27
+ Формат читается из текста команды и работает без сети; существование задачи, её присутствие в
28
+ очереди, исполнитель и то, что она ещё открыта, — только когда есть чем спросить. Нет сети
29
+ или нет токена — второй ярус молча пропускается: проверка, падающая в самолёте, перестаёт
30
+ что-либо значить.
31
+ - **Колонка задачи двигается тем же движением, что и работа.** Ветка заведена — задача
32
+ переставляется во взятые в работу, PR открыт — в разбор. Перевод идёт сразу за шагом, который
33
+ его вызвал: очередь работ читают между шагами, а не после них.
34
+ - **Отставшая колонка находится сверкой очереди, а не глазами.** Сверка судит колонку по отчёту
35
+ в обе стороны: открытый PR при задаче не в разборе и разбор без открытого PR — оба
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
+ - `git-workflow-commit` — ветка, коммит, пуш и PR от учётной записи машинной работы.
61
+ - `git-workflow-merge` — влить главную ветку в ветку задачи и разрешить конфликт.
62
+ - `git-workflow-migration` — файл миграции и прогон цепочки на одноразовом хранилище.
63
+ - `git-workflow-restart` — ручной перезапуск прода без отката на прежний образ.
64
+
65
+ ## Ловушки
66
+
67
+ - **Одна работа — одна задача, сколько бы файлов она ни задела.** Числа, за которым правка
68
+ становится второй задачей, нет: делится то, что придётся откатывать порознь. Сплошная правка,
69
+ разделённая «по объёму», кончается стиранием лишних задач, закрытием их PR и переносом
70
+ коммитов с конфликтами.
71
+ - **Задача заводится одной командой, а не набором вызовов подряд.** Очередь работ к репозиторию
72
+ обычно не привязана, и задача попадает в неё только явным добавлением: переписанный руками
73
+ шаг оставляет её вне очереди, и заметить это нечем.
74
+ - **Ветка заводится вторым вызовом, а не тем же.** Гард главной ветки отклоняет составную
75
+ «создать ветку и сразу коммитить» целиком.
76
+ - **Колонка, приведённая в порядок задним числом, ничего не значила ровно тогда, когда очередь
77
+ читали.** Перевод стоит одной команды и делается на месте, а не собирается в уборку под
78
+ конец: очередь для того и ведётся, чтобы отвечать в любой момент.
79
+ - **Сторона конфликта бывает удалением, и «сохранить обе стороны» заводит второе объявление.**
80
+ Главная ветка снимает объявление, потому что символ переехал, — в конфликте это выглядит как
81
+ сторона, которая ничего не дописала. Разбирается чтением версии главной ветки целиком, а не
82
+ по куску: обе копии сами по себе исправны, сборка и линтер зелёные.
83
+ - **Конфликт при вливании главной ветки почти всегда лежит в текстах, а не в коде.** Соседние
84
+ ветки дописывают в конец одних и тех же списков; зелёная сборка после слияния про такой
85
+ конфликт не говорит ничего.
86
+ - **PR без ревьювера, исполнителя и меток открывать нельзя.** Ревьювер не узнаёт, что его ждут,
87
+ а метки — единственное, по чему в очереди из полутора десятков PR видно род правки и её
88
+ область.
89
+ - **Заголовок PR без номера задачи не сопоставить с очередью.** В списке PR тела не видно, а
90
+ строка о закрытии задачи живёт именно там. Название при этом идёт в сделанном: задача просит
91
+ исправить, PR отчитывается, что исправлено.
92
+ - **На самом PR не гоняется ничто.** Выкатка запускается пушем в главную ветку, и выборочный
93
+ прогон по затронутому до PR не доходит: сборки, проверки текстов и браузер идут до
94
+ публикации.
95
+ - **Субагентам работа с историей запрещена полностью, включая чтение состояния.** Отложенные
96
+ изменения, спрятанные субагентом, выглядят как потеря всей работы. Историю ведёт главный
97
+ агент.
98
+ - **Подъём контейнера без явного тега образа подставляет «последний».** Приложение при этом
99
+ отвечает, и подмену видно только по пропавшим строкам нового кода в журнале.
100
+ - **Команда разработчика для миграций на живом хранилище не запускается.** Любое расхождение
101
+ состояния она лечит предложением сбросить хранилище, а в нём лежат данные владельца.
102
+ - **Переименованная миграция остаётся в хранилище под прежним именем.** Накат падает на «объект
103
+ уже существует» и лечится отметкой о применении, а не повторным накатом.
104
+ - **Флаги инструмента миграций не те, что в примерах из сети.** На неизвестный флаг команда
105
+ печатает справку, а не строку ошибки, — промах виден только в ней. Какие флаги есть сейчас,
106
+ смотрят в её собственной справке, а не в этом тексте.
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: lib-layers
3
+ kind: rule
4
+ law: lib-imports
5
+ description: Правило под закон «Импорты между либами». Брать при правке манифестов проектов, алиасов, конфигов границ, любого бареля и проверок раскладки, а также когда решается, где живёт общий символ. Готовый порядок действий — в паттернах lib-layers-new и lib-layers-move. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Импорты между либами — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/lib-imports.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
+ - `lib-layers-new` — завести или удалить либу: генератор, теги, алиас, README.
40
+ - `lib-layers-move` — перенести код между либами: порядок, границы, импорты, README обеих.
41
+
42
+ ## Ловушки
43
+
44
+ - **Либа, которую никто не импортирует, не проверена ничем.** Линтер и тесты проверяют её саму,
45
+ а не договор с потребителем: потерянное поле в модели ошибкой не считается, пока нет
46
+ вызывающего кода. Первый импортёр и есть первая проверка — слой моделей принимается после
47
+ сборки и живого прогона сценария, а не по зелёному линтеру с тестами.
48
+ - **Проверка раскладки принимается на нарушении, а не на зелёном прогоне.** Нарушение вносится
49
+ руками, прогон краснеет, правка снимается. У самих проверок тестов обычно нет, и это
50
+ единственная их приёмка.
51
+ - **Удаление каталога средствами гита оставляет то, что гит не отслеживал.** Кэш сборщика
52
+ внутри удалённой либы остаётся на диске, и проверка продолжает видеть её как домен без слоёв.
53
+ - **Пустой слой механики неотличим от слота под будущую задачу.** Проверка требует полного
54
+ набора слоёв у всех, и оба случая выглядят одинаково.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: permissions
3
+ kind: rule
4
+ law: access
5
+ description: Правило под закон «Доступ». Брать при заведении или правке обработчика серверной стороны, перехватчика входа, стража маршрута и декларации меню. Четыре вида доступа, объявление ровно одно, пресет плюс точечные правки, закрытие раздела и его адреса одной декларацией. Готовый код — в паттерне permissions-procedure. Чем это названо здесь — в implementation.md рядом.
6
+ ---
7
+
8
+ # Доступ — каким приёмом
9
+
10
+ Правило под закон `{{lawsDir}}/access.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
+ - `permissions-procedure` — объявление доступа у обработчика и закрытие раздела интерфейса.
41
+
42
+ ## Ловушки
43
+
44
+ - **Обработчик, о котором перехватчик ничего не знает, отбивается как отказ в доступе, а не
45
+ пропускается.**
46
+ - **Страж стоит на дочерних маршрутах защищённой группы, а не на самой группе.** Страж группы
47
+ отрабатывает один раз за загрузку страницы и переходов между разделами не видит.
48
+ - **Права приходят ответом профиля уже внутри защищённой группы**, поэтому страж дожидается
49
+ запуска приложения. Отказ запроса ожидание не роняет: с неизвестными правами не закрывается
50
+ ничего.
51
+ - **Метки объявления живут в утилитах домена входа, а не рядом с перехватчиком.** Их ставит
52
+ каждый домен с обработчиками, и ребро к объявлениям дешевле ребра к секрету и хранилищу.