@rt-tools/agent-kit 0.11.0 → 0.13.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 (138) hide show
  1. package/assets/checks/board-runs.github.mjs +87 -0
  2. package/assets/checks/board.github.mjs +0 -40
  3. package/assets/checks/check-board.github.mjs +39 -8
  4. package/assets/checks/check-file-size.mjs +19 -4
  5. package/assets/checks/check-schema-drift.mjs +28 -5
  6. package/assets/checks/check-state-next.mjs +10 -2
  7. package/assets/checks/rt-kit-checks.config.mjs +28 -2
  8. package/assets/commands/feedback.md +8 -0
  9. package/assets/defaults/project.sh +59 -6
  10. package/assets/defaults/turn-map.md +8 -6
  11. package/assets/hooks/browser-guard-device-id.sh +3 -1
  12. package/assets/hooks/browser-guard-no-asking.sh +3 -1
  13. package/assets/hooks/browser-guard-no-other-drivers.sh +6 -4
  14. package/assets/hooks/browser-guard-require-select.sh +4 -2
  15. package/assets/hooks/claim-guard.sh +3 -1
  16. package/assets/hooks/conscience-guard.sh +3 -1
  17. package/assets/hooks/dev-server-guard.sh +6 -4
  18. package/assets/hooks/dispatch.sh +69 -0
  19. package/assets/hooks/docs-guard.sh +6 -4
  20. package/assets/hooks/exam-guard.sh +5 -3
  21. package/assets/hooks/git-guard-delivery-folder.sh +99 -0
  22. package/assets/hooks/git-guard-delivery-signature.sh +10 -4
  23. package/assets/hooks/git-guard-delivery.sh +58 -74
  24. package/assets/hooks/git-guard-main.sh +6 -4
  25. package/assets/hooks/git-guard-push-tests.sh +8 -6
  26. package/assets/hooks/grill-gate.sh +4 -2
  27. package/assets/hooks/handoff-entry-guard.sh +4 -2
  28. package/assets/hooks/handoff-write.sh +27 -6
  29. package/assets/hooks/hook-input.sh +77 -0
  30. package/assets/hooks/lint-after-edit.sh +5 -3
  31. package/assets/hooks/override-write-guard.sh +107 -0
  32. package/assets/hooks/postmortem-guard.sh +3 -1
  33. package/assets/hooks/proposal-guard.sh +3 -1
  34. package/assets/hooks/prose-style-guard.sh +5 -3
  35. package/assets/hooks/qa-dataid-guard.sh +4 -2
  36. package/assets/hooks/rerun-guard.sh +6 -4
  37. package/assets/hooks/reuse-first-guard.sh +5 -3
  38. package/assets/hooks/rule-article.sh +99 -0
  39. package/assets/hooks/rule-source-guard.sh +126 -0
  40. package/assets/hooks/skill-gate-rearm.sh +3 -1
  41. package/assets/hooks/skill-gate.sh +23 -2
  42. package/assets/hooks/skill-loaded.sh +3 -1
  43. package/assets/hooks/sql-guard-request.sh +2 -1
  44. package/assets/hooks/sql-guard.sh +4 -2
  45. package/assets/hooks/task-flow-guard.sh +24 -4
  46. package/assets/hooks/turn-exit-guard.sh +59 -17
  47. package/assets/hooks/waiting-turn-guard.sh +3 -1
  48. package/assets/hooks/window-fill-guard.sh +6 -4
  49. package/assets/laws/work-conduct.md +5 -9
  50. package/assets/patterns/dependencies-upgrade.md +1 -1
  51. package/assets/patterns/doc-style-write.md +3 -3
  52. package/assets/patterns/git-workflow-commit.azure.md +2 -202
  53. package/assets/patterns/git-workflow-commit.github.md +2 -258
  54. package/assets/patterns/git-workflow-commit.gitlab.md +1 -217
  55. package/assets/patterns/git-workflow-docker.md +3 -3
  56. package/assets/patterns/git-workflow-merge.md +3 -2
  57. package/assets/patterns/git-workflow-migration.md +3 -3
  58. package/assets/patterns/git-workflow-pr.azure.md +224 -0
  59. package/assets/patterns/git-workflow-pr.github.md +280 -0
  60. package/assets/patterns/git-workflow-pr.gitlab.md +240 -0
  61. package/assets/patterns/git-workflow-restart.md +3 -3
  62. package/assets/patterns/git-workflow-secrets.md +3 -3
  63. package/assets/patterns/task-flow-archive.md +195 -0
  64. package/assets/patterns/task-flow-close.md +72 -240
  65. package/assets/patterns/task-flow-handoff.md +4 -4
  66. package/assets/patterns/task-flow-resume.md +5 -3
  67. package/assets/pitfalls/agent-kit.md +80 -0
  68. package/assets/pitfalls/doc-style.md +80 -0
  69. package/assets/pitfalls/git-workflow.azure.md +50 -0
  70. package/assets/pitfalls/git-workflow.github.md +78 -0
  71. package/assets/pitfalls/git-workflow.gitlab.md +49 -0
  72. package/assets/pitfalls/spec-driven.md +36 -0
  73. package/assets/pitfalls/styling-bem.md +45 -0
  74. package/assets/pitfalls/task-flow.md +62 -0
  75. package/assets/pitfalls/testing.md +70 -0
  76. package/assets/rules/deploy-flow.azure.md +114 -0
  77. package/assets/rules/deploy-flow.github.md +122 -0
  78. package/assets/rules/deploy-flow.gitlab.md +116 -0
  79. package/assets/rules/doc-style.md +25 -76
  80. package/assets/rules/git-workflow.azure.md +6 -92
  81. package/assets/rules/git-workflow.github.md +20 -128
  82. package/assets/rules/git-workflow.gitlab.md +6 -93
  83. package/assets/rules/spec-driven.md +39 -30
  84. package/assets/rules/styling-bem.md +20 -39
  85. package/assets/rules/task-flow.md +56 -222
  86. package/assets/rules/testing.md +3 -64
  87. package/assets/rules/turn-conduct.md +210 -0
  88. package/assets/rules/typescript-conventions.md +15 -0
  89. package/assets/skills/agent-kit.md +67 -89
  90. package/assets/templates/pitfalls.md +10 -0
  91. package/assets/templates/proposal.md +16 -1
  92. package/assets/templates/rule.md +5 -3
  93. package/bin/agent-kit.d.ts.map +1 -1
  94. package/bin/agent-kit.js +1 -42
  95. package/bin/agent-kit.js.map +1 -1
  96. package/lib/assets.d.ts.map +1 -1
  97. package/lib/assets.js +6 -1
  98. package/lib/assets.js.map +1 -1
  99. package/lib/cascade.d.ts.map +1 -1
  100. package/lib/cascade.js +19 -1
  101. package/lib/cascade.js.map +1 -1
  102. package/lib/commands.d.ts.map +1 -1
  103. package/lib/commands.js +1 -0
  104. package/lib/commands.js.map +1 -1
  105. package/lib/config.d.ts +16 -1
  106. package/lib/config.d.ts.map +1 -1
  107. package/lib/config.js +8 -0
  108. package/lib/config.js.map +1 -1
  109. package/lib/hooks-map.d.ts +13 -0
  110. package/lib/hooks-map.d.ts.map +1 -1
  111. package/lib/hooks-map.js +33 -1
  112. package/lib/hooks-map.js.map +1 -1
  113. package/lib/proposals.d.ts +5 -1
  114. package/lib/proposals.d.ts.map +1 -1
  115. package/lib/proposals.js +74 -5
  116. package/lib/proposals.js.map +1 -1
  117. package/lib/ship.d.ts +1 -2
  118. package/lib/ship.d.ts.map +1 -1
  119. package/lib/ship.js +0 -54
  120. package/lib/ship.js.map +1 -1
  121. package/lib/shipment.d.ts.map +1 -1
  122. package/lib/shipment.fixture.d.ts +39 -0
  123. package/lib/shipment.fixture.d.ts.map +1 -0
  124. package/lib/shipment.fixture.js +99 -0
  125. package/lib/shipment.fixture.js.map +1 -0
  126. package/lib/shipment.js +59 -7
  127. package/lib/shipment.js.map +1 -1
  128. package/package.json +1 -1
  129. package/rt-tools-agent-kit-0.13.0.tgz +0 -0
  130. package/assets/commands/agent-kit-digest.md +0 -89
  131. package/assets/commands/rules-review.md +0 -98
  132. package/assets/patterns/cargo-triage-mark.md +0 -119
  133. package/assets/rules/cargo-triage.md +0 -126
  134. package/lib/cargo-state.d.ts +0 -62
  135. package/lib/cargo-state.d.ts.map +0 -1
  136. package/lib/cargo-state.js +0 -118
  137. package/lib/cargo-state.js.map +0 -1
  138. package/rt-tools-agent-kit-0.11.0.tgz +0 -0
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: deploy-flow
3
+ kind: rule
4
+ law: delivery
5
+ description: Правило под «Закон о поставке» для дерева в Azure DevOps — та его часть, что про выкатку. Брать, когда правка едет на прод: слияние в главную ветку, конвейер, образы и их метки, чистка реестра, описание прода, цепочка миграций хранилища. Называет признак режима в образе, выкатку по sha коммита, глубину отката и сверку прода с главной веткой. Готовый код — в паттернах git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets. Не брать на заведение задачи, ветки, коммит и заявку — это правило git-workflow.
6
+ ---
7
+
8
+ # Выкатка — как это устроено здесь
9
+
10
+ Правило под закон `docs/constitution/delivery.md` — та его часть, что про прод. Закон
11
+ говорит, что должно быть верно; здесь — каким приёмом это держится в дереве, лежащем
12
+ в Azure DevOps. Работа с очередью, ветка, коммит и заявка — правило `git-workflow` под тем же
13
+ законом.
14
+
15
+ ## Как это называется здесь
16
+
17
+ | В законе | Здесь |
18
+ | -------------------------------- | -------------------------------------------------------- |
19
+ | попадание правки в главную ветку | слияние PR; чем запускается выкатка — слиянием или ручным запуском, — называет компаньон рядом |
20
+ | образ того коммита | `IMAGE_TAG=<sha>` в командах `docker compose` на сервере |
21
+ | изменение хранилища | миграция в `prisma/migrations/<метка>_<имя>/` |
22
+
23
+ ## Где это лежит
24
+
25
+ В этом дереве — таблица в `implementation.md` рядом. Пути живут там, а не здесь: правило
26
+ переносится между репозиториями, раскладка — нет, и путь, названный в правиле, врёт в первом
27
+ же дереве, которое держит код иначе.
28
+
29
+ ## Ход
30
+
31
+ Ход выкатки: что уезжает на прод, чем помечен образ и что делается со старыми.
32
+
33
+ ```mermaid
34
+ flowchart TD
35
+ A[Слияние в главную ветку] --> B{Правка задела код}
36
+ B -->|Нет| C[Шаги сборки пропускаются по признаку состава правки]
37
+ B -->|Да| D[Образ собирается и метится sha того коммита]
38
+ D --> E{Хранилище меняется этой правкой}
39
+ E -->|Да| F[Цепочка миграций прогнана с пустого хранилища до слияния]
40
+ E -->|Нет| G[Образ выкатывается по sha, а не по метке «последний»]
41
+ F --> G
42
+ G --> H[Старые образы снимаются, три последних sha остаются глубиной отката]
43
+ H --> I{Прод отвечает тем, что выкачено}
44
+ I -->|Нет| J[Разбор выкатки: перезапуск идёт по sha, а не по последней метке]
45
+ I -->|Да| K[Сверка очереди работ читает последний прогон главной ветки]
46
+ C --> K
47
+ J --> K
48
+ ```
49
+
50
+ ## Как закон применяется здесь
51
+
52
+ - **Конвейер судит по составу правки, а не гоняет всё подряд.** Шаги, которым нечего проверять,
53
+ пропускаются по признаку, посчитанному от главной ветки: ветка, не тронувшая ни строки кода,
54
+ не поднимает стенда, не снимает кадров и не собирает образов. Признак объявляется переменной
55
+ задания и считается один раз, а не переспрашивается в каждом условии. Пропущенный шаг виден в
56
+ прогоне пропущенным — молча выпавший читается как пройденный.
57
+ - **Чем запускается выкатка, называет дерево, а не правило.** У одного дерева прод едет от
58
+ слияния, у другого — ручным запуском, и сказанное здесь безусловно врёт про второе: правило
59
+ приходит в контекст каждой сессии, и прочитавший его считает влитое выкаченным. Прод,
60
+ отставший от главной ветки на сотни коммитов, так и читался поломкой приложения. Строка стоит
61
+ в компаньоне рядом, вместе со способом спросить, что выкачено на самом деле.
62
+ - **Выкатка идёт от слияния — переменные окружения, секреты и записи имён ставятся до него.**
63
+ Фильтры путей конвейера покрывают документы отдельно. Дерево с ручным запуском эту статью
64
+ читает иначе: там граница — сам запуск, и до него ставится то же самое.
65
+ - **Признак режима объявлен в образе, а не только в составе прода.** Значение, заданное
66
+ составом, действует лишь на контейнер, поднятый этим составом; ручной прогон того же образа
67
+ идёт с пустым значением, а пусто здесь означает локалхост — со всеми отладочными
68
+ умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
69
+ - **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
70
+ от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
71
+ - **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
72
+ висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
73
+ сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
74
+ через две выкатки, откатывается уже некуда.
75
+ - **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
76
+ бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
77
+ копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
78
+ - **Правка конвейера прогоняется до слияния ручным запуском.** Конвейер запускается на любой
79
+ ветке, а задание выкатки прибито условием к главной: прогон ради проверки доходит до сборок и
80
+ там кончается. Прогон команд задания на своей машине его не покрывает: он проверяет команды,
81
+ а не файл конвейера, — верность самого файла читается только по списку прогонов после пуша.
82
+ - **PR проверяется до слияния тем же конвейером, что и главная ветка.** Проверки и сборки
83
+ образов идут на конвейере проверки PR, выкатка — нет: её держит условие по главной ветке у
84
+ своего задания, а образ PR в реестр не уезжает.
85
+ - **Расхождение прода с главной веткой видно сверкой очереди работ.** Рабочий элемент уходит из
86
+ очереди слиянием, но слияние — ещё не прод: отказавшая или незапущенная выкатка не трогает ни
87
+ элемент, ни его состояние, и заметить её неоткуда. Сверка спрашивает последнюю успешную выкатку и считает, на сколько от неё ушла главная
88
+ ветка. Прогон главной ветки для этого не годится: там, где выкатку запускают рукой, слияние
89
+ прод не двигает вовсе, и прогон о нём не говорит ничего — прод отставал на 476 коммитов, а
90
+ сверка молчала. Дерево, не назвавшее рабочего потока выкатки, сверки не получает, и она
91
+ говорит об этом вслух.
92
+ - **Цепочка миграций прогоняется с пустого хранилища до слияния.** Порядок применения
93
+ лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
94
+ ветки, начатой раньше, встаёт перед той, от которой зависит.
95
+ - **Расхождение миграций со схемой меряется на теневом хранилище, а не на том, где работает
96
+ тот, кто пушит.** Оно законно несёт след любой недоделанной ветки, и сверка с ним держала бы
97
+ чужую правку. Гейт и выкатка зовут одну и ту же проверку — иначе «сошлось» станет значить в
98
+ двух местах разное.
99
+
100
+ ## Чего из закона здесь нет
101
+
102
+ Состояние прода машине не видно: сверка очереди работ спрашивает последний прогон главной
103
+ ветки и судит по нему, а отвечает ли прод той сборкой, которую он выкатил, не спрашивает
104
+ никто. Держится это тем, кто выкатывал.
105
+
106
+ Полноту чистки реестра не считает ничто: сценарий оставляет три последних sha, и промах в
107
+ его отборе виден только тогда, когда диск сервера кончился.
108
+
109
+ ## Паттерны
110
+
111
+ - `git-workflow-migration` — правка схемы хранилища и её миграций.
112
+ - `git-workflow-restart` — ручной перезапуск прода.
113
+ - `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
114
+ - `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: deploy-flow
3
+ kind: rule
4
+ law: delivery
5
+ description: Правило под «Закон о поставке» для дерева на GitHub — та его часть, что про выкатку. Брать, когда правка едет на прод: мерж в главную ветку, конвейер, образы и их метки, чистка реестра, описание прода, цепочка миграций хранилища. Называет признак режима в образе, выкатку по sha коммита, глубину отката и сверку прода с главной веткой. Готовый код — в паттернах git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets. Не брать на заведение задачи, ветки, коммит и заявку — это правило git-workflow.
6
+ ---
7
+
8
+ # Выкатка — как это устроено здесь
9
+
10
+ Правило под закон `docs/constitution/delivery.md` — та его часть, что про прод. Закон
11
+ говорит, что должно быть верно; здесь — каким приёмом это держится в дереве, лежащем
12
+ на GitHub. Работа с очередью, ветка, коммит и заявка — правило `git-workflow` под тем же
13
+ законом.
14
+
15
+ ## Как это называется здесь
16
+
17
+ | В законе | Здесь |
18
+ | -------------------------------- | -------------------------------------------------------- |
19
+ | попадание правки в главную ветку | мерж PR; чем запускается выкатка — слиянием или ручным запуском, — называет компаньон рядом |
20
+ | образ того коммита | `IMAGE_TAG=<sha>` в командах `docker compose` на сервере |
21
+ | изменение хранилища | миграция в `prisma/migrations/<метка>_<имя>/` |
22
+
23
+ ## Где это лежит
24
+
25
+ В этом дереве — таблица в `implementation.md` рядом. Пути живут там, а не здесь: правило
26
+ переносится между репозиториями, раскладка — нет, и путь, названный в правиле, врёт в первом
27
+ же дереве, которое держит код иначе.
28
+
29
+ ## Ход
30
+
31
+ Ход выкатки: что уезжает на прод, чем помечен образ и что делается со старыми.
32
+
33
+ ```mermaid
34
+ flowchart TD
35
+ A[Мерж в главную ветку] --> B{Правка задела код}
36
+ B -->|Нет| C[Шаги сборки пропускаются по признаку состава правки]
37
+ B -->|Да| D[Образ собирается и метится sha того коммита]
38
+ D --> E{Хранилище меняется этой правкой}
39
+ E -->|Да| F[Цепочка миграций прогнана с пустого хранилища до слияния]
40
+ E -->|Нет| G[Образ выкатывается по sha, а не по метке «последний»]
41
+ F --> G
42
+ G --> H[Старые образы снимаются, три последних sha остаются глубиной отката]
43
+ H --> I{Прод отвечает тем, что выкачено}
44
+ I -->|Нет| J[Разбор выкатки: перезапуск идёт по sha, а не по последней метке]
45
+ I -->|Да| K[Сверка очереди работ читает последний прогон главной ветки]
46
+ C --> K
47
+ J --> K
48
+ ```
49
+
50
+ ## Как закон применяется здесь
51
+
52
+ - **Конвейер судит по составу правки, а не гоняет всё подряд.** Шаги, которым нечего проверять,
53
+ пропускаются по признаку, посчитанному от главной ветки: ветка, не тронувшая ни строки кода,
54
+ не поднимает стенда, не снимает кадров и не собирает образов. Признак считается один раз и
55
+ объявляется выводом шага, а не переспрашивается в каждом условии. Пропущенный шаг виден в
56
+ прогоне пропущенным — молча выпавший читается как пройденный.
57
+ - **Чем запускается выкатка, называет дерево, а не правило.** У одного дерева прод едет от
58
+ мержа, у другого — ручным запуском, и сказанное здесь безусловно врёт про второе: правило
59
+ приходит в контекст каждой сессии, и прочитавший его считает влитое выкаченным. Прод,
60
+ отставший от главной ветки на сотни коммитов, так и читался поломкой приложения. Строка стоит
61
+ в компаньоне рядом, вместе со способом спросить, что выкачено на самом деле.
62
+ - **Выкатка идёт от мержа — переменные окружения, секреты и записи имён ставятся до него.**
63
+ Исключения по путям покрывают только документы. Дерево с ручным запуском эту статью читает
64
+ иначе: там граница — сам запуск, и до него ставится то же самое.
65
+ - **Признак режима объявлен в образе, а не только в составе прода.** Значение, заданное
66
+ составом, действует лишь на контейнер, поднятый этим составом; ручной прогон того же образа
67
+ идёт с пустым значением, а пусто здесь означает локалхост — со всеми отладочными
68
+ умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
69
+ - **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
70
+ от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
71
+ - **Убирает за собой и та машина, которая образы собирает.** Отбор у обеих один — своё имя
72
+ реестра, три последних sha, поднятые контейнеры остаются, — и зовётся он одним сценарием:
73
+ разойдясь, две чистки начали бы оставлять разное, а заметить это нечем. Отличаются они
74
+ хвостом: сервер снимает следом висячие слои и кэш сборки, машина сборки оставляет их себе,
75
+ иначе каждая сборка идёт как первая. Чистка на сборке не ждёт мержа: образ ветки занимает
76
+ столько же места, в реестр не уезжает вовсе и точкой отката не бывает.
77
+ - **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
78
+ висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
79
+ сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
80
+ через две выкатки, откатывается уже некуда.
81
+ - **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
82
+ бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
83
+ копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
84
+ - **Правка конвейера прогоняется до мержа ручным запуском.** `workflow_dispatch` у выкатки
85
+ запускает её на любой ветке, а сама выкатка прибита условием к главной: прогон ради проверки
86
+ доходит до сборок и там кончается. Триггер регистрируется по главной ветке, поэтому правку,
87
+ которая его заводит или переносит, ручной запуск не покрывает. Прогон команд задания на своей
88
+ машине не покрывает её тоже: он проверяет команды, а не файл конвейера, — верность самого
89
+ файла читается только по списку прогонов после пуша.
90
+ - **PR проверяется до мержа тем же конвейером, что и главная ветка.** Проверки и сборки
91
+ образов идут на событии `pull_request`, выкатка — нет: её держит условие по главной ветке у
92
+ своего задания, а образ PR в реестр не уезжает.
93
+ - **Расхождение прода с главной веткой видно сверкой очереди работ.** Задача уходит из очереди
94
+ мержем, но мерж — ещё не прод: отказавшая или незапущенная выкатка не трогает ни задачу, ни её
95
+ колонку, и заметить её неоткуда. Сверка спрашивает последнюю успешную выкатку и считает, на сколько от неё ушла главная
96
+ ветка. Прогон главной ветки для этого не годится: там, где выкатку запускают рукой, слияние
97
+ прод не двигает вовсе, и прогон о нём не говорит ничего — прод отставал на 476 коммитов, а
98
+ сверка молчала. Дерево, не назвавшее рабочего потока выкатки, сверки не получает, и она
99
+ говорит об этом вслух.
100
+ - **Цепочка миграций прогоняется с пустого хранилища до мержа.** Порядок применения
101
+ лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
102
+ ветки, начатой раньше, встаёт перед той, от которой зависит.
103
+ - **Расхождение миграций со схемой меряется на теневом хранилище, а не на том, где работает
104
+ тот, кто пушит.** Оно законно несёт след любой недоделанной ветки, и сверка с ним держала бы
105
+ чужую правку. Гейт и выкатка зовут одну и ту же проверку — иначе «сошлось» станет значить в
106
+ двух местах разное.
107
+
108
+ ## Чего из закона здесь нет
109
+
110
+ Состояние прода машине не видно: сверка очереди работ спрашивает последний прогон главной
111
+ ветки и судит по нему, а отвечает ли прод той сборкой, которую он выкатил, не спрашивает
112
+ никто. Держится это тем, кто выкатывал.
113
+
114
+ Полноту чистки реестра не считает ничто: сценарий оставляет три последних sha, и промах в
115
+ его отборе виден только тогда, когда диск сервера кончился.
116
+
117
+ ## Паттерны
118
+
119
+ - `git-workflow-migration` — правка схемы хранилища и её миграций.
120
+ - `git-workflow-restart` — ручной перезапуск прода.
121
+ - `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
122
+ - `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: deploy-flow
3
+ kind: rule
4
+ law: delivery
5
+ description: Правило под «Закон о поставке» для дерева на GitLab — та его часть, что про выкатку. Брать, когда правка едет на прод: слияние в главную ветку, конвейер, образы и их метки, чистка реестра, описание прода, цепочка миграций хранилища. Называет признак режима в образе, выкатку по sha коммита, глубину отката и сверку прода с главной веткой. Готовый код — в паттернах git-workflow-migration, git-workflow-restart, git-workflow-docker и git-workflow-secrets. Не брать на заведение задачи, ветки, коммит и заявку — это правило git-workflow.
6
+ ---
7
+
8
+ # Выкатка — как это устроено здесь
9
+
10
+ Правило под закон `docs/constitution/delivery.md` — та его часть, что про прод. Закон
11
+ говорит, что должно быть верно; здесь — каким приёмом это держится в дереве, лежащем
12
+ на GitLab. Работа с очередью, ветка, коммит и заявка — правило `git-workflow` под тем же
13
+ законом.
14
+
15
+ ## Как это называется здесь
16
+
17
+ | В законе | Здесь |
18
+ | -------------------------------- | -------------------------------------------------------- |
19
+ | попадание правки в главную ветку | слияние MR; чем запускается выкатка — слиянием или ручным запуском, — называет компаньон рядом |
20
+ | образ того коммита | `IMAGE_TAG=<sha>` в командах `docker compose` на сервере |
21
+ | изменение хранилища | миграция в `prisma/migrations/<метка>_<имя>/` |
22
+
23
+ ## Где это лежит
24
+
25
+ В этом дереве — таблица в `implementation.md` рядом. Пути живут там, а не здесь: правило
26
+ переносится между репозиториями, раскладка — нет, и путь, названный в правиле, врёт в первом
27
+ же дереве, которое держит код иначе.
28
+
29
+ ## Ход
30
+
31
+ Ход выкатки: что уезжает на прод, чем помечен образ и что делается со старыми.
32
+
33
+ ```mermaid
34
+ flowchart TD
35
+ A[Слияние в главную ветку] --> B{Правка задела код}
36
+ B -->|Нет| C[Шаги сборки пропускаются по признаку состава правки]
37
+ B -->|Да| D[Образ собирается и метится sha того коммита]
38
+ D --> E{Хранилище меняется этой правкой}
39
+ E -->|Да| F[Цепочка миграций прогнана с пустого хранилища до слияния]
40
+ E -->|Нет| G[Образ выкатывается по sha, а не по метке «последний»]
41
+ F --> G
42
+ G --> H[Старые образы снимаются, три последних sha остаются глубиной отката]
43
+ H --> I{Прод отвечает тем, что выкачено}
44
+ I -->|Нет| J[Разбор выкатки: перезапуск идёт по sha, а не по последней метке]
45
+ I -->|Да| K[Сверка очереди работ читает последний прогон главной ветки]
46
+ C --> K
47
+ J --> K
48
+ ```
49
+
50
+ ## Как закон применяется здесь
51
+
52
+ - **Конвейер судит по составу правки, а не гоняет всё подряд.** Шаги, которым нечего проверять,
53
+ пропускаются по признаку, посчитанному от главной ветки: ветка, не тронувшая ни строки кода,
54
+ не поднимает стенда, не снимает кадров и не собирает образов. Правила `rules:changes` считают
55
+ это сами, но по путям, а не по составу правки — совпадение пути ещё не значит, что задета
56
+ сборка, поэтому признак объявляется явно и один раз. Пропущенный шаг виден в прогоне
57
+ пропущенным — молча выпавший читается как пройденный.
58
+ - **Чем запускается выкатка, называет дерево, а не правило.** У одного дерева прод едет от
59
+ слияния, у другого — ручным запуском, и сказанное здесь безусловно врёт про второе: правило
60
+ приходит в контекст каждой сессии, и прочитавший его считает влитое выкаченным. Прод,
61
+ отставший от главной ветки на сотни коммитов, так и читался поломкой приложения. Строка стоит
62
+ в компаньоне рядом, вместе со способом спросить, что выкачено на самом деле.
63
+ - **Выкатка идёт от слияния — переменные окружения, секреты и записи имён ставятся до него.**
64
+ Правила `only`/`rules` конвейера покрывают документы отдельно. Дерево с ручным запуском эту
65
+ статью читает иначе: там граница — сам запуск, и до него ставится то же самое.
66
+ - **Признак режима объявлен в образе, а не только в составе прода.** Значение, заданное
67
+ составом, действует лишь на контейнер, поднятый этим составом; ручной прогон того же образа
68
+ идёт с пустым значением, а пусто здесь означает локалхост — со всеми отладочными
69
+ умолчаниями, которые он разрешает. Умолчание образа задаётся в самом образе.
70
+ - **Образы выкатываются по sha коммита, а не по метке «последний».** Метка в реестре отстаёт
71
+ от главной ветки, и прод молча возвращается к прежней версии, продолжая отвечать.
72
+ - **Выкатка убирает за собой старые образы, оставляя три последних sha.** Помеченный sha образ
73
+ висячим не бывает никогда, и чистка висячего его не касается: за полгода они съедают диск
74
+ сервера целиком. Три sha — это глубина отката, и меньше брать нельзя: поломка, замеченная
75
+ через две выкатки, откатывается уже некуда.
76
+ - **Описание прода правится вместе с составом прода.** Устройство, путь запроса, гейты и
77
+ бэкапы описаны текстами вне слоёв правил, и ни линтер, ни сборка их не читают: расхождение
78
+ копится молча, а читают эти тексты как действующие. Пару стережёт гард документов.
79
+ - **Правка конвейера прогоняется до слияния ручным запуском.** Конвейер запускается на любой
80
+ ветке, а задание выкатки прибито правилом к главной: прогон ради проверки доходит до сборок и
81
+ там кончается. Прогон команд задания на своей машине его не покрывает: он проверяет команды,
82
+ а не файл конвейера, — верность самого файла читается только по списку конвейеров после
83
+ пуша, и синтаксис отдельно судит проверка `.gitlab-ci.yml` в проекте.
84
+ - **PR проверяется до слияния тем же конвейером, что и главная ветка.** Проверки и сборки
85
+ образов идут на конвейере запроса слияния, выкатка — нет: её держит правило по главной ветке
86
+ у своего задания, а образ PR в реестр не уезжает.
87
+ - **Расхождение прода с главной веткой видно сверкой очереди работ.** Задача уходит из очереди
88
+ слиянием, но слияние — ещё не прод: отказавшая или незапущенная выкатка не трогает ни задачу,
89
+ ни её список, и заметить её неоткуда. Сверка спрашивает последнюю успешную выкатку и считает, на сколько от неё ушла главная
90
+ ветка. Прогон главной ветки для этого не годится: там, где выкатку запускают рукой, слияние
91
+ прод не двигает вовсе, и прогон о нём не говорит ничего — прод отставал на 476 коммитов, а
92
+ сверка молчала. Дерево, не назвавшее рабочего потока выкатки, сверки не получает, и она
93
+ говорит об этом вслух.
94
+ - **Цепочка миграций прогоняется с пустого хранилища до слияния.** Порядок применения
95
+ лексикографический по имени каталога, а метку времени ставит момент создания: миграция из
96
+ ветки, начатой раньше, встаёт перед той, от которой зависит.
97
+ - **Расхождение миграций со схемой меряется на теневом хранилище, а не на том, где работает
98
+ тот, кто пушит.** Оно законно несёт след любой недоделанной ветки, и сверка с ним держала бы
99
+ чужую правку. Гейт и выкатка зовут одну и ту же проверку — иначе «сошлось» станет значить в
100
+ двух местах разное.
101
+
102
+ ## Чего из закона здесь нет
103
+
104
+ Состояние прода машине не видно: сверка очереди работ спрашивает последний прогон главной
105
+ ветки и судит по нему, а отвечает ли прод той сборкой, которую он выкатил, не спрашивает
106
+ никто. Держится это тем, кто выкатывал.
107
+
108
+ Полноту чистки реестра не считает ничто: сценарий оставляет три последних sha, и промах в
109
+ его отборе виден только тогда, когда диск сервера кончился.
110
+
111
+ ## Паттерны
112
+
113
+ - `git-workflow-migration` — правка схемы хранилища и её миграций.
114
+ - `git-workflow-restart` — ручной перезапуск прода.
115
+ - `git-workflow-docker` — образы на своей машине: демон, реестр, сборка под платформу сервера.
116
+ - `git-workflow-secrets` — ключи внешних служб: где лежат, как заводятся, что говорит их состояние.
@@ -12,6 +12,9 @@ description: Правило под «Закон о документации пр
12
12
  Устройство спеков и слоёв документации — правило `spec-driven` под тем же законом; здесь
13
13
  только формулировки.
14
14
 
15
+ **Холодная часть:** `pitfalls.md` рядом — ловушки, грабли, на которые уже наступали.
16
+ Грузится по требованию, а не вместе с правилом.
17
+
15
18
  ## Как это называется здесь
16
19
 
17
20
  | В законе | Здесь |
@@ -58,42 +61,62 @@ flowchart TD
58
61
  которые едут в репозиторий: личный черновик, закрытый `.gitignore` или
59
62
  `.git/info/exclude`, проверка не читает — мёртвая ссылка в нём держала гейт пуша, хотя ни
60
63
  в одну ветку этот файл не попадёт.
64
+ <!-- rt-when: *.md -->
65
+
61
66
  - **Голое имя и каталог судятся наравне с полным путём.** Имя без каталога ищется по всему
62
67
  дереву, каталог — среди каталогов; дерево спрашивается у системы контроля версий, иначе
63
68
  каталоги, начинающиеся с точки, не видны и всё, что в них лежит, читалось бы как
64
69
  несуществующее. Половина строк в таблицах «Где это лежит» — как раз каталоги.
70
+ <!-- rt-when: *.md -->
71
+
65
72
  - **Описание прошлого из проверки путей выведено целиком.** Архив по устройству называет
66
73
  файлы, которых уже нет, и правкой это не лечится. Папка задачи выведена по той же причине:
67
74
  раздел находок в ходе работы перечисляет ровно то, чего в дереве нет.
75
+ <!-- rt-when: *.md -->
76
+
68
77
  - **Переносимый текст из сверки адресов выведен, как архив.** Закон, правило и паттерн написаны
69
78
  для любого дерева этого класса, и адреса в них принадлежат тому дереву, куда текст ложится:
70
79
  `libs/common/util` там, где корни зовутся иначе, — пример, а не мёртвая ссылка. Разложенную
71
80
  копию проверка узнаёт по шапке раскладки, исходник — по каталогу, названному в настройке; без
72
81
  этого сверка краснеет на полторы сотни строк, ни одна из которых не чинится здесь.
82
+ <!-- rt-when: *.md -->
83
+
73
84
  - **Указатель каталога сверяется с его содержимым обеими сторонами.** Записи каталог набирает
74
85
  быстрее, чем читают его указатель, и промах не виден ни в сборке, ни в браузере: запись,
75
86
  приехавшая слиянием соседней ветки, просто не попадает в таблицу. Сверенный руками указатель
76
87
  расходится снова через сутки.
88
+ <!-- rt-when: *.md -->
89
+
77
90
  - **Имя, названное затем, чтобы сказать «его нет», стоит в списке исключений поимённо.**
78
91
  Отличить такое упоминание от ссылки машине нечем, а текст без него теряет смысл: правило и
79
92
  замысел предупреждают именно о снятом. Туда же — то, что появляется только после сборки,
80
93
  имена веток и правила линтеров: выглядят адресом, адресом не являются.
94
+ <!-- rt-when: *.md -->
95
+
81
96
  - **Документ едет в том же коммите, что и правка, которую он описывает.** Обход — строка
82
97
  `Docs-skip: <причина>` в теле коммита; пустая причина не принимается.
98
+ <!-- rt-when: *.md -->
99
+
83
100
  - **Документ не длиннее предела длины.** Текст, который не влезает на экран целиком, дописывают
84
101
  в конец, не перечитав начала, — так в одном документе и оказываются два ответа на один вопрос.
85
- Предел тот же, что у кода, и считается так же — все строки; выросший спек делится на
86
- поддомены, а не переносит границу. Описание прошлого из счёта выведено: архив по устройству
102
+ Предел у текста свой, ниже, чем у кода, и считается так же — все строки; выросший спек
103
+ делится на поддомены, а не переносит границу. Два числа вместо одного заведены потому, что
104
+ тексту порог нужен раньше: у кода длину стережёт ещё и линтер, а у прозы — только это число. Описание прошлого из счёта выведено: архив по устройству
87
105
  перечисляет то, чего в дереве уже нет, а папка задачи умирает со слиянием.
106
+ <!-- rt-when: *.md -->
107
+
88
108
  - **Файл, уезжающий в описание прошлого, называет в шапке свой прежний адрес.** Записи архива
89
109
  ссылались на него, пока он был живым, и после переезда эти ссылки ведут в пустоту: проверка
90
110
  путей архив не читает вовсе, поэтому промах не краснеет никогда. Найти переехавшее нечем —
91
111
  имя записи архива с прежним адресом не совпадает, и поиск по нему её не показывает. Одна
92
112
  строка в шапке дешевле правки всех ссылающихся записей и прошлого не трогает.
113
+ <!-- rt-when: *.md -->
114
+
93
115
  - **Текст, называющий состояние машины, устаревает без единой правки в дереве.** Ловушка о том,
94
116
  что на машине установлено, верна в день, когда её пишут, и становится неправдой сама собой —
95
117
  ни одна сверка этого не видит: они читают дерево, а состарилась машина. Утверждение о машине
96
118
  пишется способом её спросить: команда и то, с чем сверять ответ, вместо снимка ответа.
119
+ <!-- rt-when: *.md -->
97
120
 
98
121
  ## Чего из закона здесь нет
99
122
 
@@ -127,77 +150,3 @@ flowchart TD
127
150
 
128
151
  Читается этот список раньше остального: правило говорит, как формулировать, а скил дерева — что
129
152
  у документа этого рода обязательно есть, вплоть до второго файла рядом.
130
-
131
- ## Ловушки
132
-
133
- - **Оставшаяся работа не записывается в документ, а заводится задачей.** `docs/BACKLOG.md`
134
- держит только то, что задачей не бывает: договорённости и решения, которые решено не
135
- править. Признак — утверждение остаётся, если править его никто не собирается. «Сделать
136
- потом» в плане, README или спеке — второй список работ: он расходится с бордой молча, а
137
- разбирать его потом дороже, чем завести задачу сразу. Из 1411 строк документа действующими
138
- оказались 71, и на разбор остальных ушла отдельная задача. Как разбирать накопившееся —
139
- паттерн `doc-style-sweep`.
140
- - **Словарь действует и на разговор с владельцем, не только на файлы.** Он приходит в контекст
141
- на запуске сессии, поэтому «не читал» основанием не бывает. Слово из левой колонки «Так не
142
- пишем» всплывало именно в ответах: в дереве его уже вычистили, а в PR о сделанном оно
143
- оставалось, и владелец читал ровно то слово, от которого отказались.
144
- - **Термин берётся из `docs/GLOSSARY.md`, а не придумывается на месте.** Слова, которого там
145
- нет, у читателя нет тоже: «журнал приложения» простоял в спеке почты, пока владелец не
146
- спросил, что это, — оказалось, логи бэкенда, а слово «журнал» здесь уже занято журналом
147
- событий. Новое слово либо заводится в словаре вместе с правкой, либо заменяется тем, что
148
- уже есть.
149
- - **Проход по словарю глазами слово не находит.** «Формулировки приведены к словарю» означает
150
- ровно те строки, которые в тот момент читали: «спека» пережила такой проход и осталась в
151
- соседней строке того же файла. Слово из левой колонки таблицы «Так не пишем» вычищается
152
- грепом по всему дереву, а не вычиткой. Форма задаётся точно: «спек» — документ — склоняется
153
- в «спека» и «спеки» тоже, и совпадений по корню законных больше, чем нарушений; ищутся
154
- сочетания («спеки на … нет», «спека проверяет»), а не корень.
155
- - **Снятое имя вычищается одним грепом по всему дереву:** правила, их зеркала в скилах,
156
- документы и комментарии. Описание того, чего в коде уже нет, читается как действующее
157
- указание.
158
- - **У снятого слова второе значение возвращается после сплошной замены, а не обходится до
159
- неё.** Слово снимают ровно потому, что оно стояло над двумя вещами, и второе значение при
160
- этом остаётся законным. Отобрать его заранее нечем: какое из двух значений в строке, видно
161
- только по соседнему тексту, а строк бывают сотни. Порядок обратный — сплошная замена, затем
162
- сплошной просмотр самой правки, и найденное второе значение возвращается поимённо. Из 353
163
- замен так вернулись шесть, и две первые были поломкой: сверка печатала новое имя дважды
164
- подряд, а комментарий обещал «поломку вместо PR о том, что долгов нет». Просматривается
165
- правка, а не дерево после неё: в дереве обе стороны выглядят одинаково верными.
166
- - **Поиск по дереву не покрывает того, что уже уехало наружу.** Заголовок задачи и её тело,
167
- заголовок PR и его тело, заголовки коммитов лежат вне файлов, и проверки текстов их не
168
- читают вовсе. Вычистив слово в дереве, обходят те же места в очереди работ и в истории:
169
-
170
- ```bash
171
- <клиент хостинга> api "<путь к PR>" --jq '.title, .body' | grep -i '<слово>'
172
- <клиент хостинга> api "<путь к задаче>" --jq '.title, .body' | grep -i '<слово>'
173
- git log --format='%s%n%b' <база>..HEAD | grep -i '<слово>'
174
- ```
175
-
176
- Заголовок PR правится вызовом хостинга, заголовок коммита — только переписыванием ветки,
177
- поэтому его проверяют до пуша. Выдуманное слово было вычищено из трёх файлов и объявлено
178
- снятым, а в заголовке PR и в заголовке коммита осталось — владелец прочитал именно его.
179
-
180
- - **Число в тексте пересчитывается командой в том же коммите, где пишется.** Оно стареет
181
- внутри одной ветки: «шестнадцать пар» стало неправдой через два коммита после того, как
182
- было написано, и нашёл это владелец, а не проверка. Число, которое придётся пересчитывать
183
- при каждой правке, лучше не писать вовсе. Число, полученное разбором текста, сверяется на
184
- выборке руками до того, как его называют: разбор, не знающий второй формы записи, ошибается
185
- молча — «51 пункт без задачи» оказался шестью, потому что номер стоял и отдельной строкой, и
186
- в заголовке подраздела.
187
- - **Названная в тексте проверка запускается, а не пересказывается.** «Проверка есть» и
188
- «проверка проходит» — разные утверждения, и второго в тексте обычно нет вовсе. Из четырёх
189
- проверок, названных правилом, три оказались не в том состоянии, в каком текст их описывает:
190
- одна отдавала полтора десятка замечаний, вторая переписывала файлы самим запуском, третья
191
- была красной и роняла общую сводку вместе с собой. Ни одна из трёх не входила в выкатку,
192
- поэтому молчание было полным. Проверку, которая переписывает файлы, запускают на чистом
193
- дереве: иначе её правки уедут чужим коммитом.
194
- - **Сделанность читается по дереву, а не по тексту, который о ней написан.** Это верно в обе
195
- стороны: строка про README обеих либ была вычеркнута как сделанная, а README остался с
196
- прежним числом импортёров; задача, названная владельцу несделанной, оказалась наполовину
197
- закрытой и покрытой сценариями хука. Пункт плана и тело задачи описывают день, когда их
198
- написали, и с тех пор не менялись.
199
- - **Комментарий в файле — такое же утверждение, как строка в документе.** Обоснование «строки
200
- идут во всю ширину панели, иначе подсветка обрывается» было выдумано, прожило три сессии и
201
- каждый раз читалось как основание вёрстку не трогать.
202
- - **Чужие проекты не упоминаются нигде** — ни имени репозитория, ни «портировано из», ни
203
- ссылок на его файлы. Описывается то, что код делает здесь, в терминах этого проекта.