@rt-tools/agent-kit 0.5.3 → 0.6.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.
- package/assets/checks/check-file-size.mjs +127 -0
- package/assets/checks/rt-kit-checks.config.mjs +10 -0
- package/assets/defaults/gate-map.sh +90 -34
- package/assets/defaults/project.sh +26 -3
- package/assets/hooks/skill-gate-layers.sh +156 -0
- package/assets/hooks/skill-gate.sh +11 -2
- package/assets/laws/code-structure.md +3 -0
- package/assets/laws/delivery.md +9 -0
- package/assets/laws/observability.md +46 -0
- package/assets/laws/project-documentation.md +4 -0
- package/assets/laws/reuse-first.md +2 -0
- package/assets/laws/verifiability.md +5 -0
- package/assets/patterns/browser-verification-stand.md +22 -2
- package/assets/patterns/doc-style-trace.md +111 -0
- package/assets/patterns/git-workflow-commit.github.md +1 -1
- package/assets/patterns/git-workflow-docker.md +203 -0
- package/assets/patterns/git-workflow-secrets.md +93 -0
- package/assets/patterns/observability-record.md +114 -0
- package/assets/patterns/ownership-session-procedure.md +102 -0
- package/assets/patterns/seo-verify.md +1 -1
- package/assets/patterns/spec-driven-rule.md +5 -0
- package/assets/patterns/styling-bem-sheet.md +178 -0
- package/assets/patterns/task-flow-close.md +20 -0
- package/assets/patterns/task-flow-resume.md +5 -0
- package/assets/patterns/translations-content.md +107 -0
- package/assets/patterns/translations-key.md +1 -1
- package/assets/rules/angular-patterns.md +5 -0
- package/assets/rules/browser-verification.md +17 -12
- package/assets/rules/component-structure.md +6 -2
- package/assets/rules/doc-style.md +16 -0
- package/assets/rules/git-workflow.azure.md +45 -1
- package/assets/rules/git-workflow.github.md +52 -1
- package/assets/rules/git-workflow.gitlab.md +46 -1
- package/assets/rules/lists.md +13 -0
- package/assets/rules/observability.md +147 -0
- package/assets/rules/ownership-scope.md +5 -2
- package/assets/rules/ownership-session.md +124 -0
- package/assets/rules/permissions.md +23 -0
- package/assets/rules/pricing.md +4 -0
- package/assets/rules/reuse-first.md +9 -0
- package/assets/rules/seo.md +57 -9
- package/assets/rules/shared-code.md +6 -0
- package/assets/rules/spec-driven.md +9 -0
- package/assets/rules/styling-bem.md +34 -1
- package/assets/rules/task-flow.md +5 -0
- package/assets/rules/testing.md +46 -8
- package/assets/rules/translations.md +11 -5
- package/assets/rules/typescript-conventions.md +5 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.6.0.tgz +0 -0
- package/rt-tools-agent-kit-0.5.3.tgz +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: git-workflow
|
|
3
3
|
kind: rule
|
|
4
4
|
law: delivery
|
|
5
|
-
description: Правило под «Закон о поставке» для дерева в Azure DevOps. Брать на заведение задачи, ветки, коммит, пуш, создание PR, слияние, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет рабочий элемент как начало работы, его состояние как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав PR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration и git-workflow-
|
|
5
|
+
description: Правило под «Закон о поставке» для дерева в Azure DevOps. Брать на заведение задачи, ветки, коммит, пуш, создание PR, слияние, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет рабочий элемент как начало работы, его состояние как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав PR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Поставка — как это устроено здесь
|
|
@@ -63,6 +63,11 @@ description: Правило под «Закон о поставке» для д
|
|
|
63
63
|
- **Задачи, чинящиеся одной правкой, сливаются до слияния ветки.** Вторая закрывается как
|
|
64
64
|
дубликат, а недостающее из неё дописывается в первую. После слияния слить уже нельзя: ветка
|
|
65
65
|
въехала, и откатывается она целиком.
|
|
66
|
+
- **Работа, которую одним заходом не закрыть, помечена в двух местах, и они сверяются.** Метка
|
|
67
|
+
на доске и строка о заходах с передачей в линии работ говорят одно и то же двум читателям:
|
|
68
|
+
исполнитель открывает карточку раньше, чем линию, а планирует по линии. Одна пометка без
|
|
69
|
+
другой лжёт молча, поэтому сверка очереди судит пару в обе стороны. Помечается только то, что
|
|
70
|
+
законно не делится: пометка объёма правом делить не становится.
|
|
66
71
|
- **Слияние в главную ветку выкатывает прод.** Фильтры путей конвейера покрывают документы
|
|
67
72
|
отдельно, поэтому переменные окружения, секреты и записи имён ставятся до слияния, а не
|
|
68
73
|
после.
|
|
@@ -72,6 +77,24 @@ description: Правило под «Закон о поставке» для д
|
|
|
72
77
|
умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
|
|
73
78
|
- **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
|
|
74
79
|
от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
|
|
80
|
+
- **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
|
|
81
|
+
висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
|
|
82
|
+
сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
|
|
83
|
+
через две выкатки, откатывается уже некуда.
|
|
84
|
+
- **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
|
|
85
|
+
бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
|
|
86
|
+
копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
|
|
87
|
+
- **Правка конвейера прогоняется до слияния ручным запуском.** Конвейер запускается на любой
|
|
88
|
+
ветке, а задание выкатки прибито условием к главной: прогон ради проверки доходит до сборок и
|
|
89
|
+
там кончается. Прогон команд задания на своей машине его не покрывает: он проверяет команды,
|
|
90
|
+
а не файл конвейера, — верность самого файла читается только по списку прогонов после пуша.
|
|
91
|
+
- **Отчёт проверяется до слияния тем же конвейером, что и главная ветка.** Проверки и сборки
|
|
92
|
+
образов идут на конвейере проверки PR, выкатка — нет: её держит условие по главной ветке у
|
|
93
|
+
своего задания, а образ отчёта в реестр не уезжает.
|
|
94
|
+
- **Расхождение прода с главной веткой видно сверкой очереди работ.** Рабочий элемент уходит из
|
|
95
|
+
очереди слиянием, но слияние — ещё не прод: отказавшая выкатка не трогает ни элемент, ни его
|
|
96
|
+
состояние, и заметить её неоткуда. Сверка спрашивает последний прогон главной ветки и судит
|
|
97
|
+
только завершённый: идущий ещё может кончиться выкаткой.
|
|
75
98
|
- **Цепочка миграций прогоняется с пустого хранилища до слияния.** Порядок применения
|
|
76
99
|
лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
|
|
77
100
|
ветки, начатой раньше, встаёт перед той, от которой зависит.
|
|
@@ -81,6 +104,10 @@ description: Правило под «Закон о поставке» для д
|
|
|
81
104
|
заголовок читается списком, а свободный текст — только целиком.
|
|
82
105
|
- **Перед пушем прогоняются все линтеры, а не один.** Линтер кода обычно не читает файлы
|
|
83
106
|
стилей вовсе, и правила оформления без второго прогона не проверяет ничто.
|
|
107
|
+
- **Сборка входит в набор наравне с линтом и юнитами.** Линтер типов не читает, а юниты читают
|
|
108
|
+
только то, что импортировано тестом: ошибка типов в непокрытом коде доживает до сборки
|
|
109
|
+
образа, то есть до слияния. Четыре слияния подряд так и уехали в главную ветку, ломая
|
|
110
|
+
выкатку.
|
|
84
111
|
- **Рабочий элемент привязывается к PR при создании, а не после.** `az repos pr create`
|
|
85
112
|
принимает `--work-items`; привязка второй командой обходится молча, когда у токена нет права
|
|
86
113
|
править чужой элемент, и PR остаётся ни с чем не связанным.
|
|
@@ -124,6 +151,8 @@ description: Правило под «Закон о поставке» для д
|
|
|
124
151
|
- `git-workflow-merge` — главная ветка влита в ветку задачи, конфликт разобран.
|
|
125
152
|
- `git-workflow-migration` — правка схемы хранилища и её миграций.
|
|
126
153
|
- `git-workflow-restart` — ручной перезапуск прода.
|
|
154
|
+
- `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
|
|
155
|
+
- `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
|
|
127
156
|
|
|
128
157
|
## Ловушки
|
|
129
158
|
|
|
@@ -148,6 +177,21 @@ description: Правило под «Закон о поставке» для д
|
|
|
148
177
|
записи, на следующий вызов это не переносится: PR открывают токеном учётной записи машинной
|
|
149
178
|
работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
|
|
150
179
|
смена записи ради пуша утекла в публикацию — отчёт вышел от владельца.
|
|
180
|
+
- **Невалидный файл конвейера виден прогоном нулевой длительности сразу после пуша.** Прогон
|
|
181
|
+
заводится и кончается на разборе файла, не начав ни одного задания: в списке он стоит
|
|
182
|
+
отказом, а внутри нет ни задания, ни лога — читается только длительность. Поэтому список
|
|
183
|
+
прогонов ветки смотрится тем же движением, что и пуш: `az pipelines runs list` по своей
|
|
184
|
+
ветке.
|
|
185
|
+
- **`online` у агента на своей машине означает запущенный процесс, а не работающий конвейер.**
|
|
186
|
+
Две стороны сходятся отдельно: требования заданий и возможности самого агента в его пуле.
|
|
187
|
+
Пока пересечения нет, агент стоит `online` и не берёт ничего, а задания ждут размещённого
|
|
188
|
+
пула — по состоянию это выглядит настроенным. Владельцу называют выполненное задание с его
|
|
189
|
+
номером, а не строку состояния.
|
|
190
|
+
- **Вход в реестр образов из агента, запущенного службой, отказывает молча.** Служба идёт без
|
|
191
|
+
сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
|
|
192
|
+
отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
|
|
193
|
+
не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
|
|
194
|
+
`git-workflow-docker`.
|
|
151
195
|
- **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
|
|
152
196
|
разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
|
|
153
197
|
входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: git-workflow
|
|
3
3
|
kind: rule
|
|
4
4
|
law: delivery
|
|
5
|
-
description: Правило под «Закон о поставке» для дерева на GitHub. Брать на заведение задачи, ветки, коммит, пуш, создание PR, мерж, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет задачу на борде как начало работы, колонку задачи как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав PR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration и git-workflow-
|
|
5
|
+
description: Правило под «Закон о поставке» для дерева на GitHub. Брать на заведение задачи, ветки, коммит, пуш, создание PR, мерж, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет задачу на борде как начало работы, колонку задачи как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав PR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Поставка — как это устроено здесь
|
|
@@ -73,6 +73,11 @@ description: Правило под «Закон о поставке» для д
|
|
|
73
73
|
- **Задачи, чинящиеся одной правкой, сливаются до мержа.** Вторая стирается вместе с номером,
|
|
74
74
|
а недостающее из неё дописывается в первую. После мержа слить уже нельзя: ветка въехала, и
|
|
75
75
|
откатывается она целиком.
|
|
76
|
+
- **Работа, которую одним заходом не закрыть, помечена в двух местах, и они сверяются.** Метка
|
|
77
|
+
на борде и строка о заходах с передачей в линии работ говорят одно и то же двум читателям:
|
|
78
|
+
исполнитель открывает карточку раньше, чем линию, а планирует по линии. Одна пометка без
|
|
79
|
+
другой лжёт молча, поэтому сверка очереди судит пару в обе стороны. Помечается только то, что
|
|
80
|
+
законно не делится: пометка объёма правом делить не становится.
|
|
76
81
|
- **Мерж в главную ветку выкатывает прод.** Исключения по путям покрывают только документы,
|
|
77
82
|
поэтому переменные окружения, секреты и записи имён ставятся до мержа, а не после.
|
|
78
83
|
- **Признак режима объявлен в образе, а не только в составе прода.** Значение, заданное
|
|
@@ -81,6 +86,26 @@ description: Правило под «Закон о поставке» для д
|
|
|
81
86
|
умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
|
|
82
87
|
- **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
|
|
83
88
|
от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
|
|
89
|
+
- **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
|
|
90
|
+
висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
|
|
91
|
+
сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
|
|
92
|
+
через две выкатки, откатывается уже некуда.
|
|
93
|
+
- **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
|
|
94
|
+
бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
|
|
95
|
+
копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
|
|
96
|
+
- **Правка конвейера прогоняется до мержа ручным запуском.** `workflow_dispatch` у выкатки
|
|
97
|
+
запускает её на любой ветке, а сама выкатка прибита условием к главной: прогон ради проверки
|
|
98
|
+
доходит до сборок и там кончается. Триггер регистрируется по главной ветке, поэтому правку,
|
|
99
|
+
которая его заводит или переносит, ручной запуск не покрывает. Прогон команд задания на своей
|
|
100
|
+
машине не покрывает её тоже: он проверяет команды, а не файл конвейера, — верность самого
|
|
101
|
+
файла читается только по списку прогонов после пуша.
|
|
102
|
+
- **Отчёт проверяется до мержа тем же конвейером, что и главная ветка.** Проверки и сборки
|
|
103
|
+
образов идут на событии `pull_request`, выкатка — нет: её держит условие по главной ветке у
|
|
104
|
+
своего задания, а образ отчёта в реестр не уезжает.
|
|
105
|
+
- **Расхождение прода с главной веткой видно сверкой очереди работ.** Задача уходит из очереди
|
|
106
|
+
мержем, но мерж — ещё не прод: отказавшая выкатка не трогает ни задачу, ни её колонку, и
|
|
107
|
+
заметить её неоткуда. Сверка спрашивает последний прогон главной ветки и судит только
|
|
108
|
+
завершённый: идущий ещё может кончиться выкаткой.
|
|
84
109
|
- **Цепочка миграций прогоняется с пустого хранилища до мержа.** Порядок применения
|
|
85
110
|
лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
|
|
86
111
|
ветки, начатой раньше, встаёт перед той, от которой зависит.
|
|
@@ -90,6 +115,9 @@ description: Правило под «Закон о поставке» для д
|
|
|
90
115
|
заголовок читается списком, а свободный текст — только целиком.
|
|
91
116
|
- **Перед пушем прогоняются все линтеры, а не один.** Линтер кода обычно не читает файлы
|
|
92
117
|
стилей вовсе, и правила оформления без второго прогона не проверяет ничто.
|
|
118
|
+
- **Сборка входит в набор наравне с линтом и юнитами.** Линтер типов не читает, а юниты читают
|
|
119
|
+
только то, что импортировано тестом: ошибка типов в непокрытом коде доживает до сборки
|
|
120
|
+
образа, то есть до мержа. Четыре мержа подряд так и уехали в главную ветку, ломая выкатку.
|
|
93
121
|
- **Автор PR не может быть его ревьювером.** Запрос разбора на самого себя GitHub принимает и
|
|
94
122
|
молча не создаёт — разбор при этом выглядит запрошенным.
|
|
95
123
|
- **Метки, исполнитель и ревьювер PR ставятся вызовами `gh api`, а не `gh pr edit`.** На
|
|
@@ -131,6 +159,8 @@ description: Правило под «Закон о поставке» для д
|
|
|
131
159
|
- `git-workflow-merge` — главная ветка влита в ветку задачи, конфликт разобран.
|
|
132
160
|
- `git-workflow-migration` — правка схемы хранилища и её миграций.
|
|
133
161
|
- `git-workflow-restart` — ручной перезапуск прода.
|
|
162
|
+
- `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
|
|
163
|
+
- `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
|
|
134
164
|
|
|
135
165
|
## Ловушки
|
|
136
166
|
|
|
@@ -154,6 +184,27 @@ description: Правило под «Закон о поставке» для д
|
|
|
154
184
|
записи, на следующий вызов это не переносится: PR открывают токеном учётной записи машинной
|
|
155
185
|
работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
|
|
156
186
|
смена записи ради пуша утекла в публикацию — отчёт вышел от владельца.
|
|
187
|
+
- **Невалидный файл конвейера виден прогоном нулевой длительности сразу после пуша.** GitHub
|
|
188
|
+
заводит такой прогон и на ветке, на которую ни один триггер не подписан: в списке он стоит
|
|
189
|
+
отказом, а внутри у него нет ни задания, ни лога — читается только длительность. Поэтому
|
|
190
|
+
список прогонов ветки смотрится тем же движением, что и пуш — `gh run list --branch <ветка>`.
|
|
191
|
+
Один такой отказ простоял в списке до мержа, и на него никто не посмотрел: выкатка после
|
|
192
|
+
мержа отказала ровно тем же.
|
|
193
|
+
- **Контекст `runner` в `env` задания отбивает весь файл конвейера.** Там доступны только
|
|
194
|
+
`github`, `needs`, `strategy`, `matrix`, `vars`, `secrets` и `inputs`; `runner` появляется на
|
|
195
|
+
уровне шага, где то же значение приходит переменной окружения. Такой файл не принимается
|
|
196
|
+
вовсе: прогон кончается за ноль секунд, не начав ни одного задания. Разбор YAML этого не
|
|
197
|
+
ловит — синтаксис верный, а доступность контекстов синтаксисом не является.
|
|
198
|
+
- **`online` у раннера на своей машине означает запущенный процесс, а не работающий
|
|
199
|
+
конвейер.** Две стороны сходятся отдельно: `runs-on` у заданий и метки самого раннера. Пока
|
|
200
|
+
пересечения нет, раннер стоит `online` и не берёт ничего, а задания уходят в облако — по
|
|
201
|
+
состоянию это выглядит настроенным. Владельцу называют выполненное задание с его номером, а
|
|
202
|
+
не строку состояния.
|
|
203
|
+
- **Вход в реестр образов из раннера, запущенного службой, отказывает молча.** Служба идёт без
|
|
204
|
+
сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
|
|
205
|
+
отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
|
|
206
|
+
не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
|
|
207
|
+
`git-workflow-docker`.
|
|
157
208
|
- **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
|
|
158
209
|
разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
|
|
159
210
|
входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: git-workflow
|
|
3
3
|
kind: rule
|
|
4
4
|
law: delivery
|
|
5
|
-
description: Правило под «Закон о поставке» для дерева на GitLab. Брать на заведение задачи, ветки, коммит, пуш, создание MR, слияние, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет задачу на борде как начало работы, колонку задачи как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав MR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration и git-workflow-
|
|
5
|
+
description: Правило под «Закон о поставке» для дерева на GitLab. Брать на заведение задачи, ветки, коммит, пуш, создание MR, слияние, а также на правку схемы хранилища, её миграций и вызовы миграций. Называет задачу на борде как начало работы, колонку задачи как ход работы, соответствие задачи и ветки один к одному, имя ветки, формат коммита, учётную запись машинной работы, обязательный состав MR, гарды поставки и сверку очереди работ. Готовый код — в паттернах git-workflow-commit, git-workflow-merge, git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Поставка — как это устроено здесь
|
|
@@ -62,6 +62,11 @@ description: Правило под «Закон о поставке» для д
|
|
|
62
62
|
- **Задачи, чинящиеся одной правкой, сливаются до слияния ветки.** Вторая стирается вместе с
|
|
63
63
|
номером, а недостающее из неё дописывается в первую. После слияния слить уже нельзя: ветка
|
|
64
64
|
въехала, и откатывается она целиком.
|
|
65
|
+
- **Работа, которую одним заходом не закрыть, помечена в двух местах, и они сверяются.** Метка
|
|
66
|
+
на доске и строка о заходах с передачей в линии работ говорят одно и то же двум читателям:
|
|
67
|
+
исполнитель открывает карточку раньше, чем линию, а планирует по линии. Одна пометка без
|
|
68
|
+
другой лжёт молча, поэтому сверка очереди судит пару в обе стороны. Помечается только то, что
|
|
69
|
+
законно не делится: пометка объёма правом делить не становится.
|
|
65
70
|
- **Слияние в главную ветку выкатывает прод.** Правила `only`/`rules` конвейера покрывают
|
|
66
71
|
документы отдельно, поэтому переменные окружения, секреты и записи имён ставятся до слияния,
|
|
67
72
|
а не после.
|
|
@@ -71,6 +76,25 @@ description: Правило под «Закон о поставке» для д
|
|
|
71
76
|
умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
|
|
72
77
|
- **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
|
|
73
78
|
от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
|
|
79
|
+
- **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
|
|
80
|
+
висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
|
|
81
|
+
сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
|
|
82
|
+
через две выкатки, откатывается уже некуда.
|
|
83
|
+
- **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
|
|
84
|
+
бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
|
|
85
|
+
копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
|
|
86
|
+
- **Правка конвейера прогоняется до слияния ручным запуском.** Конвейер запускается на любой
|
|
87
|
+
ветке, а задание выкатки прибито правилом к главной: прогон ради проверки доходит до сборок и
|
|
88
|
+
там кончается. Прогон команд задания на своей машине его не покрывает: он проверяет команды,
|
|
89
|
+
а не файл конвейера, — верность самого файла читается только по списку конвейеров после
|
|
90
|
+
пуша, и синтаксис отдельно судит проверка `.gitlab-ci.yml` в проекте.
|
|
91
|
+
- **Отчёт проверяется до слияния тем же конвейером, что и главная ветка.** Проверки и сборки
|
|
92
|
+
образов идут на конвейере запроса слияния, выкатка — нет: её держит правило по главной ветке
|
|
93
|
+
у своего задания, а образ отчёта в реестр не уезжает.
|
|
94
|
+
- **Расхождение прода с главной веткой видно сверкой очереди работ.** Задача уходит из очереди
|
|
95
|
+
слиянием, но слияние — ещё не прод: отказавшая выкатка не трогает ни задачу, ни её список, и
|
|
96
|
+
заметить её неоткуда. Сверка спрашивает последний конвейер главной ветки и судит только
|
|
97
|
+
завершённый: идущий ещё может кончиться выкаткой.
|
|
74
98
|
- **Цепочка миграций прогоняется с пустого хранилища до слияния.** Порядок применения
|
|
75
99
|
лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
|
|
76
100
|
ветки, начатой раньше, встаёт перед той, от которой зависит.
|
|
@@ -80,6 +104,10 @@ description: Правило под «Закон о поставке» для д
|
|
|
80
104
|
заголовок читается списком, а свободный текст — только целиком.
|
|
81
105
|
- **Перед пушем прогоняются все линтеры, а не один.** Линтер кода обычно не читает файлы
|
|
82
106
|
стилей вовсе, и правила оформления без второго прогона не проверяет ничто.
|
|
107
|
+
- **Сборка входит в набор наравне с линтом и юнитами.** Линтер типов не читает, а юниты читают
|
|
108
|
+
только то, что импортировано тестом: ошибка типов в непокрытом коде доживает до сборки
|
|
109
|
+
образа, то есть до слияния. Четыре слияния подряд так и уехали в главную ветку, ломая
|
|
110
|
+
выкатку.
|
|
83
111
|
- **Слияние по кнопке «Merge when pipeline succeeds» не заменяет проверок до пуша.** Конвейер
|
|
84
112
|
видит только то, что уже отправлено, а отправленная красная ветка занимает очередь работ и
|
|
85
113
|
выглядит готовой к разбору.
|
|
@@ -121,6 +149,8 @@ description: Правило под «Закон о поставке» для д
|
|
|
121
149
|
- `git-workflow-merge` — главная ветка влита в ветку задачи, конфликт разобран.
|
|
122
150
|
- `git-workflow-migration` — правка схемы хранилища и её миграций.
|
|
123
151
|
- `git-workflow-restart` — ручной перезапуск прода.
|
|
152
|
+
- `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
|
|
153
|
+
- `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
|
|
124
154
|
|
|
125
155
|
## Ловушки
|
|
126
156
|
|
|
@@ -144,6 +174,21 @@ description: Правило под «Закон о поставке» для д
|
|
|
144
174
|
записи, на следующий вызов это не переносится: MR открывают токеном учётной записи машинной
|
|
145
175
|
работы, и от того, чьей записью он открыт, зависит, кого можно назначить ревьювером. Однажды
|
|
146
176
|
смена записи ради пуша утекла в публикацию — отчёт вышел от владельца.
|
|
177
|
+
- **Невалидный файл конвейера виден отказом сразу после пуша, а не упавшим заданием.** Конвейер
|
|
178
|
+
на такой файл не заводится вовсе: в списке стоит запись об ошибке разбора, а внутри нет ни
|
|
179
|
+
задания, ни лога. Поэтому список конвейеров ветки смотрится тем же движением, что и пуш —
|
|
180
|
+
`glab ci list --branch <ветка>`, — а сам файл до пуша судит проверка `.gitlab-ci.yml` в
|
|
181
|
+
проекте.
|
|
182
|
+
- **`online` у раннера на своей машине означает запущенный процесс, а не работающий
|
|
183
|
+
конвейер.** Две стороны сходятся отдельно: `tags` у заданий и теги самого раннера. Пока
|
|
184
|
+
пересечения нет, раннер стоит `online` и не берёт ничего, а задания ждут общего раннера — по
|
|
185
|
+
состоянию это выглядит настроенным. Владельцу называют выполненное задание с его номером, а
|
|
186
|
+
не строку состояния.
|
|
187
|
+
- **Вход в реестр образов из раннера, запущенного службой, отказывает молча.** Служба идёт без
|
|
188
|
+
сеанса пользователя, а клиент реестра уходит в системный помощник хранения ключей и получает
|
|
189
|
+
отказ во взаимодействии — задание падает до сборки. Свой каталог настроек с пустым помощником
|
|
190
|
+
не спасает: клиент переписывает пустое значение обратно сам. Готовые команды — паттерн
|
|
191
|
+
`git-workflow-docker`.
|
|
147
192
|
- **Новое рабочее дерево получает только то, что лежит в индексе.** `git worktree add`
|
|
148
193
|
разворачивает коммит, а настройки, ключи, локальные разрешения и зависимости в коммит не
|
|
149
194
|
входят: свежее дерево выглядит готовым и упирается в нехватку не сразу, а на первом гарде,
|
package/assets/rules/lists.md
CHANGED
|
@@ -30,11 +30,24 @@ description: Правило под «Закон о списке записей»
|
|
|
30
30
|
|
|
31
31
|
## Как закон применяется здесь
|
|
32
32
|
|
|
33
|
+
- **Страница собирается общим компонентом страницы списка, а не своей разметкой.** Заголовок,
|
|
34
|
+
панель действий, зона прокрутки и переключатель страниц одинаковы у всех списков, и
|
|
35
|
+
переписанные заново они расходятся молча.
|
|
36
|
+
- **Механика экрана берётся из общей основы списочного экрана, а не пишется заново.** Экран
|
|
37
|
+
домена объявляет стор, ключ таблицы, поля сортировки и столбцы; выборка из адреса и в адрес,
|
|
38
|
+
страница, её размер, сортировка, тост отказа и переходы в панель уже там.
|
|
39
|
+
- **Таблицу экран объявляет сам и кладёт внутрь шаблона.** Обернуть её нельзя: столбцы она
|
|
40
|
+
собирает собственным запросом по содержимому, и через посредника они до неё не доходят.
|
|
33
41
|
- **Список собирается `<префикс>-table`, а не своей разметкой.** Скелетоны, пустое состояние,
|
|
34
42
|
карточки на узком экране и настройка столбцов — входы таблицы; свой
|
|
35
43
|
`@if (rows().length === 0)` означает, что экран собран мимо неё.
|
|
36
44
|
- **Строки объявляются на `rowsTable.displayedColumns()`, а не на своём списке.** Столбец с
|
|
37
45
|
меню таблица добавляет сама.
|
|
46
|
+
- **Заголовок сортируемой колонки называет поле сервера, а не ключ колонки.** Колонка и поле
|
|
47
|
+
совпадают не всегда, и пока в разметке стоит ключ колонки, экран держит две карты перевода в
|
|
48
|
+
обе стороны.
|
|
49
|
+
- **Сортируема та колонка, у чьей ячейки шапки стоит заголовок сортировки.** Отдельного
|
|
50
|
+
признака рядом со списком столбцов нет, и расходиться нечему.
|
|
38
51
|
- **Клик по строке открывает запись, а меню — для действий над ней.** Вид нажимаемой строки
|
|
39
52
|
даёт `clickable`, активацию мышью и с клавиатуры — `vmTableRow`; клик по кнопке внутри строки
|
|
40
53
|
активацией не считается.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: observability
|
|
3
|
+
kind: rule
|
|
4
|
+
law: observability
|
|
5
|
+
description: Правило под «Закон о наблюдаемости». Брать при правке логгера, контекста запроса, домена отказов и домена оповещений, при заведении новой строки лога и когда решается, что владелец узнает об отказе. Называет уровни, номер обращения, вычистку секретов, сводку старта и то, что уходит наружу при отказе. Готовый код — в паттерне observability-record.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Наблюдаемость — как это устроено здесь
|
|
9
|
+
|
|
10
|
+
Правило под закон `docs/constitution/observability.md`. Закон говорит, что владелец должен
|
|
11
|
+
знать о работе приложения; здесь — как это названо в этом дереве, где лежит и чего пока нет.
|
|
12
|
+
|
|
13
|
+
## Как это называется здесь
|
|
14
|
+
|
|
15
|
+
| В законе | Здесь |
|
|
16
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| то, что приложение о себе пишет | логи приложения: одна строка на каждый вызов логгера, в машинном виде |
|
|
18
|
+
| ступень важности | уровень: от подробностей разбора до отказа, поднявшего процесс |
|
|
19
|
+
| номер обращения | идентификатор запроса, он же заголовок ответа |
|
|
20
|
+
| признак, по которому находятся все отказы одного обращения | тот же номер обращения — он стоит в каждой строке лога |
|
|
21
|
+
| подробности отказа | разобранная причина: класс, текст, код протокола, код и подробности от хранилища, срезанный стек |
|
|
22
|
+
| общий текст ошибки наружу | внутренняя ошибка без подробностей |
|
|
23
|
+
| вычистка секретов | замена значений по имени поля |
|
|
24
|
+
| отказ в хранилище | то, что домен отказов сохранил: группа отказов и её вхождения |
|
|
25
|
+
| то, с чем приложение поднялось | сводка старта: одна строка лога с версией, портом, адресом хранилища и списками возможностей — включённых, выключенных и сломанных |
|
|
26
|
+
|
|
27
|
+
## Где это лежит
|
|
28
|
+
|
|
29
|
+
В этом дереве — таблица в `implementation.md` рядом. Пути живут там, а не здесь: правило
|
|
30
|
+
переносится между репозиториями, раскладка — нет, и путь, названный в правиле, врёт в первом
|
|
31
|
+
же дереве, которое держит код иначе.
|
|
32
|
+
|
|
33
|
+
## Как закон применяется здесь
|
|
34
|
+
|
|
35
|
+
- **Номер обращения заводится один раз на запрос и стоит в каждой строке лога о нём.** По
|
|
36
|
+
времени строки одного обращения не отобрать: обращений бывает десяток в секунду.
|
|
37
|
+
- **Номер обращения уходит вызывающему заголовком ответа и в подробностях отказа.** Он же стоит
|
|
38
|
+
в логах, поэтому названный человеком номер ищется прямым отбором. Заголовок при этом открыт
|
|
39
|
+
странице чужого домена: без явного разрешения браузер его не отдаёт.
|
|
40
|
+
- **Номер, пришедший снаружи, чистится и укорачивается, а пустой заводится заново.** Значение
|
|
41
|
+
из заголовка приходит от кого угодно, а попадает в отбор по хранилищу.
|
|
42
|
+
- **Наружу уходит код и общий текст ошибки, подробности остаются в логах.** Иначе гость на
|
|
43
|
+
сломанной выкатке прочитает имя колонки и устройство хранилища.
|
|
44
|
+
- **Отказ по вводу и правам пишется отдельно от поломки и без стека.** Это сработавшая
|
|
45
|
+
проверка. На одном уровне с поломками она забивает тревогу опечатками гостей.
|
|
46
|
+
- **Причина отказа разбирается в одном месте.** Иначе одна и та же ошибка приходит в логи
|
|
47
|
+
тремя разными формами.
|
|
48
|
+
- **Поля строки лога вычищаются всегда, а не по решению того, кто пишет.** Решать на каждом
|
|
49
|
+
вызове, есть ли в полях секрет, — значит однажды ошибиться.
|
|
50
|
+
- **Приложение при старте пишет, с чем поднялось.** Половина возможностей включается наличием
|
|
51
|
+
переменной окружения и без неё молча выключена. Иначе на вопрос «почему там не работает то,
|
|
52
|
+
что работает локально» отвечают чтением настроек прода по ssh.
|
|
53
|
+
- **В сводке старта стоят имена возможностей и их состояние, но не значения переменных.**
|
|
54
|
+
Состояния разложены тремя списками, а не картой «имя → состояние»: вычистка работает по
|
|
55
|
+
имени ключа, и карта приехала бы в лог вычищенной ровно там, где состояние и нужно.
|
|
56
|
+
- **Возможность, включаемая парой ключей, знает третье состояние.** Половины пары лежат по
|
|
57
|
+
разные стороны поставки, и заполнить можно ровно одну; тогда возможность не выключена и не
|
|
58
|
+
включена, а сломана — списком из двух состояний этот случай назвать нечем, и он читается как
|
|
59
|
+
включённый.
|
|
60
|
+
- **Порог уровня решает, появится ли строка лога в выводе, но не в хранилище отказов.** Порог
|
|
61
|
+
ставится ради объёма вывода, и при высоком пороге отобранные строки нижнего уровня пропали бы
|
|
62
|
+
из хранилища молча.
|
|
63
|
+
- **Отобранная строка лога сохраняется в хранилище отказом.** Отбирается уровень отказа и всё,
|
|
64
|
+
что выше, и строки уровнем ниже — по списку имён, объявленному в коде.
|
|
65
|
+
- **Логгер отдаёт отказ приёмнику, а хранилища не видит.** Интерфейс приёмника объявлен рядом с
|
|
66
|
+
логгером, исполняет его домен отказов, и ставится он извне при старте.
|
|
67
|
+
- **Строки лога клиента хранилища, домена отказов и домена оповещений в приёмник не идут.**
|
|
68
|
+
Отсекается источник, а не момент записи: медленная вставка в таблицу отказов сама порождает
|
|
69
|
+
строку лога клиента хранилища, и признаком «я внутри записи» её не поймать. Домен оповещений
|
|
70
|
+
отсечён по той же причине: сбой оповещения стал бы новым отказом, тот — новым оповещением.
|
|
71
|
+
- **Обращение к чужой службе идёт с явным пределом ожидания.** Без него молчащая — не
|
|
72
|
+
отказавшая — служба держит соединение до умолчания среды, а это минуты: отказа нет,
|
|
73
|
+
записывать нечего, и владельцу такое молчание неотличимо от исправной работы. Предел
|
|
74
|
+
называется числом рядом с клиентом, потому что цена ожидания у каждой службы своя.
|
|
75
|
+
- **Отправка наружу заводит свою строку до обращения, а исход дописывается в неё после.**
|
|
76
|
+
Строку заводит тот, кто видит хранилище, а не тот, кто отправляет: клиент внешней службы
|
|
77
|
+
хранилища не видит вовсе. Она же служит замком — второе обращение по той же записи не
|
|
78
|
+
уходит, — и по незакрытой строке видно разницу между «идёт прямо сейчас» и «упало посреди
|
|
79
|
+
отправки».
|
|
80
|
+
- **Запись отказа не задерживает ответ и не роняет запрос.** Между логгером и хранилищем стоит
|
|
81
|
+
очередь с пределом; переполненная очередь отбрасывает новый отказ и считает отброшенное.
|
|
82
|
+
- **Контекст запроса снимается в момент вызова логгера, а не в момент записи.** К моменту
|
|
83
|
+
записи хранилище исполнения уже отдано следующему запросу.
|
|
84
|
+
- **Записанное владелец читает своим разделом, закрытым отдельным правом.** Группы своего
|
|
85
|
+
владения, а под группой — её вхождения с причиной, полями строки лога и телами.
|
|
86
|
+
- **Хранилище не растёт без предела: раз в сутки лишнее и старое удаляются.** Удаляются
|
|
87
|
+
вхождения: сперва лишние за пределом, потом старые за сроком. Группа, у которой после этого
|
|
88
|
+
не осталось ни одного вхождения, уходит третьим шагом — и только если она старше часа: между
|
|
89
|
+
её заведением и первым вхождением проходит отдельный запрос.
|
|
90
|
+
- **Предел хранилища назван числом строк, а не байтами.** Удаление физический размер таблицы не
|
|
91
|
+
уменьшает, и условие «размер под пределом» не стало бы верным никогда.
|
|
92
|
+
- **О новом отказе владелец узнаёт сам — строкой журнала событий и письмом.** Обе дороги
|
|
93
|
+
открывает один порог: новая группа или группа, молчавшая дольше суток.
|
|
94
|
+
- **В письме нет ничего, что закрыто правом на экран отказов.** Оно уходит на адрес, который
|
|
95
|
+
правами не закрыт ничем, и подробности в нём обошли бы право почтой.
|
|
96
|
+
- **Частоту отказов владелец читает кривой над лентой: столбик — ведёрко выбранного периода.**
|
|
97
|
+
Счётчик группы говорит, сколько раз она случилась, но не когда: по нему не отличить поломку,
|
|
98
|
+
которая идёт потоком сейчас, от набравшейся за месяц.
|
|
99
|
+
- **Тревогу поднимает рост поломок, а не всех отказов.** Отклонённый вызов — сработавшая
|
|
100
|
+
проверка, и таких девять из десяти: на их фоне рост поломок не заметен вовсе.
|
|
101
|
+
- **Всплеск считается по последнему закрытому ведёрку, текущее правилу не отдаётся.** Оно ещё
|
|
102
|
+
набирается, и в начале каждого периода сравнение с ним показывало бы падение частоты.
|
|
103
|
+
- **Частоту разбирает такт расписания, а не запрос экрана.** Кривая считает тревогу при каждом
|
|
104
|
+
ответе, но экран владелец может и не открыть, а узнать о всплеске должен без этого.
|
|
105
|
+
- **О всплеске владелец узнаёт строкой журнала и письмом; повтор письма держит
|
|
106
|
+
предохранитель.** Одно происшествие занимает в ленте одну строку, а письмо о затяжной
|
|
107
|
+
поломке нужно и назавтра.
|
|
108
|
+
|
|
109
|
+
## Чего из закона здесь нет
|
|
110
|
+
|
|
111
|
+
Отказ, случившийся до подъёма приложения, записать некуда: хранилища в этот момент ещё нет.
|
|
112
|
+
Такие остаются только в выводе контейнера. Туда же уходит отказ самого хранилища: его строки
|
|
113
|
+
лога отобраны из отказов целиком, иначе поломка хранилища порождает поток, который сам себя
|
|
114
|
+
разгоняет.
|
|
115
|
+
|
|
116
|
+
Список отобранных имён нижнего уровня не сверяется ни с чем. Новое место, которому надо в
|
|
117
|
+
хранилище, дописывает себя в него руками, а забытое молча остаётся только в выводе.
|
|
118
|
+
|
|
119
|
+
Правильность выбора уровня не проверяет ничто. Новое место само решает, какой уровень взять, и
|
|
120
|
+
ошибку видно только при чтении кода.
|
|
121
|
+
|
|
122
|
+
Полнота сводки старта не сверяется ничем. Имена возможностей перечислены руками, а переменную
|
|
123
|
+
окружения читают десятки файлов по всем доменам: новая возможность, забывшая дописать себя в
|
|
124
|
+
сводку, молча не попадёт ни в один из трёх списков — и на проде будет выглядеть не выключенной,
|
|
125
|
+
а несуществующей. Само чтение переменной окружения поэтому и требует этого правила вторым
|
|
126
|
+
слоем: гард видит обращение к окружению в тексте правки, но не то, дописали себя в сводку или
|
|
127
|
+
нет.
|
|
128
|
+
|
|
129
|
+
## Паттерны
|
|
130
|
+
|
|
131
|
+
- `observability-record` — как завести новую строку лога.
|
|
132
|
+
|
|
133
|
+
## Ловушки
|
|
134
|
+
|
|
135
|
+
- **Контекст запроса живёт в хранилище исполнения и в отложенную работу не переезжает.**
|
|
136
|
+
Отложенная запись прочитает контекст того обращения, которое заняло место исходного. Снимать
|
|
137
|
+
контекст надо в момент вызова логгера.
|
|
138
|
+
- **Логгер ставится на всё приложение, поэтому строки каркаса идут тем же путём, что и свои.**
|
|
139
|
+
Всё, что каркас пишет о себе, попадает в тот же вывод и в тот же отбор.
|
|
140
|
+
- **Отказ потока приходит после того, как ответ начался.** Управление возвращается, когда отдан
|
|
141
|
+
только заголовок. Без обёртки такой отказ не попадёт в логи вовсе.
|
|
142
|
+
- **Сериализация строки лога не должна бросать исключение.** Циклическая ссылка в полях иначе
|
|
143
|
+
уронит запрос, ради лога которого её и складывали.
|
|
144
|
+
- **Ключ, в который заворачивают чужое тело для вычистки, выбирается по правилам вычистки.**
|
|
145
|
+
Она работает по имени ключа, и голое значение мимо неё проходит вовсе, — но ключ, который сам
|
|
146
|
+
числится свободным текстом, увозит тело в хранилище отметкой о вычистке целиком. Новая
|
|
147
|
+
обёртка сверяется со списками ключей до того, как её так назвали.
|
|
@@ -59,5 +59,8 @@ description: Правило под «Закон о владеющей сущно
|
|
|
59
59
|
вызывающего:** первое отвечает `FailedPrecondition`, второе — `NotFound`.
|
|
60
60
|
- Таблица владеющих сущностей читается целиком одним запросом — она маленькая, и выборки ей не
|
|
61
61
|
нужно.
|
|
62
|
-
-
|
|
63
|
-
|
|
62
|
+
- **Выбор сущности живёт в общем сторе, а рисует переключатель тот экран, которому он нужен.**
|
|
63
|
+
Выбор переживает переход между разделами, но экран без своего переключателя показывает то,
|
|
64
|
+
что выбрали на другом, — и это читается как чужие числа в своём разделе. Где переключатель
|
|
65
|
+
стоит, названо в именах дерева; снаружи выбора нет вовсе: пользователь приходит на страницу
|
|
66
|
+
конкретной сущности.
|