@rt-tools/agent-kit 0.16.1 → 0.18.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 (136) hide show
  1. package/assets/checks/board-epics.github.mjs +123 -0
  2. package/assets/checks/board-gh.github.mjs +121 -0
  3. package/assets/checks/board-paths.github.mjs +88 -0
  4. package/assets/checks/board-runs.github.mjs +8 -0
  5. package/assets/checks/board-titles.github.mjs +66 -0
  6. package/assets/checks/board.github.mjs +77 -73
  7. package/assets/checks/check-board.github.mjs +56 -7
  8. package/assets/checks/check-file-size.mjs +10 -2
  9. package/assets/checks/check-glossary.mjs +170 -0
  10. package/assets/checks/check-hook-scope.mjs +126 -0
  11. package/assets/checks/check-profile-drift.mjs +195 -0
  12. package/assets/checks/check-push-gate.mjs +59 -1
  13. package/assets/checks/check-schema-drift.mjs +12 -5
  14. package/assets/checks/check-specs.mjs +1 -1
  15. package/assets/checks/rt-kit-checks.config.mjs +13 -0
  16. package/assets/checks/spec-anchors.mjs +2 -2
  17. package/assets/checks/spec-contract.mjs +9 -0
  18. package/assets/defaults/gate-map.sh +13 -4
  19. package/assets/defaults/project.sh +31 -108
  20. package/assets/defaults/shell.sh +139 -0
  21. package/assets/docs/GLOSSARY.md +1 -1
  22. package/assets/hooks/browser-device-id.sh +20 -4
  23. package/assets/hooks/browser-guard-device-id.sh +5 -2
  24. package/assets/hooks/browser-guard-no-other-drivers.sh +41 -2
  25. package/assets/hooks/claim-guard.sh +22 -1
  26. package/assets/hooks/docs-guard.sh +1 -1
  27. package/assets/hooks/exam-guard.sh +85 -12
  28. package/assets/hooks/git-guard-delivery-conflict.sh +85 -0
  29. package/assets/hooks/git-guard-delivery-folder.sh +19 -0
  30. package/assets/hooks/git-guard-delivery-signature.sh +14 -5
  31. package/assets/hooks/git-guard-delivery.sh +54 -2
  32. package/assets/hooks/git-guard-push-tests.sh +21 -1
  33. package/assets/hooks/grill-gate-ask.sh +25 -0
  34. package/assets/hooks/grill-gate.sh +75 -11
  35. package/assets/hooks/lint-after-edit.sh +44 -16
  36. package/assets/hooks/proposal-guard.sh +11 -4
  37. package/assets/hooks/rule-source-guard.sh +8 -13
  38. package/assets/hooks/skill-gate-layers.sh +7 -0
  39. package/assets/hooks/skill-gate.sh +29 -0
  40. package/assets/hooks/task-context-load.sh +32 -0
  41. package/assets/hooks/task-flow-context.sh +194 -0
  42. package/assets/hooks/task-flow-draft-guard.sh +109 -0
  43. package/assets/hooks/task-flow-guard.sh +27 -159
  44. package/assets/hooks/turn-exit-guard.sh +53 -88
  45. package/assets/hooks/waiting-turn-guard.sh +65 -2
  46. package/assets/hooks/window-fill-guard.sh +5 -1
  47. package/assets/hooks/work-start-guard.sh +166 -0
  48. package/assets/hooks/write-targets.sh +24 -0
  49. package/assets/laws/delivery.md +19 -0
  50. package/assets/laws/frontend-application.md +4 -0
  51. package/assets/laws/verifiability.md +44 -0
  52. package/assets/laws/work-conduct.md +15 -0
  53. package/assets/patterns/browser-verification-measure.md +3 -1
  54. package/assets/patterns/browser-verification-stand.md +17 -4
  55. package/assets/patterns/doc-style-write.md +62 -2
  56. package/assets/patterns/git-workflow-commit.github.md +33 -5
  57. package/assets/patterns/git-workflow-docker.md +22 -0
  58. package/assets/patterns/git-workflow-freshness.md +87 -0
  59. package/assets/patterns/git-workflow-merge.md +41 -0
  60. package/assets/patterns/git-workflow-migration.md +11 -0
  61. package/assets/patterns/git-workflow-pr.github.md +12 -1
  62. package/assets/patterns/git-workflow-restart.md +18 -0
  63. package/assets/patterns/git-workflow-secrets.md +14 -0
  64. package/assets/patterns/git-workflow-stack.md +93 -1
  65. package/assets/patterns/lib-layers-move.md +4 -0
  66. package/assets/patterns/spec-driven-domain.md +47 -2
  67. package/assets/patterns/spec-driven-rule.md +16 -4
  68. package/assets/patterns/spec-driven-sweep.md +57 -0
  69. package/assets/patterns/status-report-table.github.md +1 -1
  70. package/assets/patterns/task-flow-archive.md +58 -16
  71. package/assets/patterns/task-flow-close.md +106 -23
  72. package/assets/patterns/task-flow-handoff.md +14 -2
  73. package/assets/patterns/task-flow-resume.md +35 -8
  74. package/assets/patterns/task-flow-start.md +60 -22
  75. package/assets/patterns/testing-e2e.md +23 -0
  76. package/assets/patterns/turn-entry-map.md +1 -1
  77. package/assets/pitfalls/agent-kit.md +71 -3
  78. package/assets/pitfalls/doc-style.md +15 -0
  79. package/assets/pitfalls/git-workflow.github.md +88 -0
  80. package/assets/pitfalls/spec-driven.md +22 -0
  81. package/assets/pitfalls/task-flow.md +113 -0
  82. package/assets/pitfalls/testing.md +6 -0
  83. package/assets/pitfalls/turn-conduct.md +49 -0
  84. package/assets/rules/browser-verification.md +58 -0
  85. package/assets/rules/deploy-flow.azure.md +8 -0
  86. package/assets/rules/deploy-flow.github.md +27 -0
  87. package/assets/rules/deploy-flow.gitlab.md +8 -0
  88. package/assets/rules/doc-style.md +20 -0
  89. package/assets/rules/git-workflow.azure.md +22 -2
  90. package/assets/rules/git-workflow.github.md +127 -118
  91. package/assets/rules/git-workflow.gitlab.md +17 -4
  92. package/assets/rules/lists.md +5 -0
  93. package/assets/rules/observability.needs-app.md +4 -0
  94. package/assets/rules/reuse-first.md +14 -0
  95. package/assets/rules/shared-code.md +5 -0
  96. package/assets/rules/spec-driven.md +33 -15
  97. package/assets/rules/task-flow.md +132 -126
  98. package/assets/rules/testing.md +41 -2
  99. package/assets/rules/turn-conduct.md +73 -57
  100. package/assets/rules/turn-entry.md +6 -0
  101. package/assets/samples/tasks/_template/grill.md +5 -0
  102. package/assets/samples/tasks/_template/plan.md +3 -0
  103. package/assets/skills/agent-kit.md +108 -76
  104. package/assets/templates/postmortem.md +5 -1
  105. package/bin/agent-kit.d.ts.map +1 -1
  106. package/bin/agent-kit.js +30 -6
  107. package/bin/agent-kit.js.map +1 -1
  108. package/lib/catalog.d.ts.map +1 -1
  109. package/lib/catalog.js +2 -1
  110. package/lib/catalog.js.map +1 -1
  111. package/lib/commands.d.ts.map +1 -1
  112. package/lib/commands.js +96 -7
  113. package/lib/commands.js.map +1 -1
  114. package/lib/hooks-map.d.ts +26 -0
  115. package/lib/hooks-map.d.ts.map +1 -1
  116. package/lib/hooks-map.js +58 -2
  117. package/lib/hooks-map.js.map +1 -1
  118. package/lib/sections.d.ts +6 -0
  119. package/lib/sections.d.ts.map +1 -1
  120. package/lib/sections.js +19 -0
  121. package/lib/sections.js.map +1 -1
  122. package/lib/shipment.d.ts +2 -0
  123. package/lib/shipment.d.ts.map +1 -1
  124. package/lib/shipment.fixture.d.ts +5 -0
  125. package/lib/shipment.fixture.d.ts.map +1 -1
  126. package/lib/shipment.fixture.js +7 -0
  127. package/lib/shipment.fixture.js.map +1 -1
  128. package/lib/shipment.js +13 -1
  129. package/lib/shipment.js.map +1 -1
  130. package/lib/sync.d.ts +35 -3
  131. package/lib/sync.d.ts.map +1 -1
  132. package/lib/sync.js +59 -8
  133. package/lib/sync.js.map +1 -1
  134. package/package.json +1 -1
  135. package/rt-tools-agent-kit-0.18.0.tgz +0 -0
  136. package/rt-tools-agent-kit-0.16.1.tgz +0 -0
@@ -2,7 +2,7 @@
2
2
  name: git-workflow-stack
3
3
  kind: pattern
4
4
  rule: git-workflow
5
- description: Паттерн правила git-workflow. Брать, когда из одного основания заведено больше двух веток и все ждут слияния: единица работы, порядок вливания, перевливание главной по факту конфликта, сложение у общих указателей. Один конфликт — паттерн git-workflow-merge.
5
+ description: Паттерн правила git-workflow. Брать, когда работы идут одна за другой либо когда из одного основания уже заведено больше двух веток: ветвление чередой от предыдущей, основание заявки, порядок вливания снизу вверх, перевливание главной по факту конфликта. Один конфликт — паттерн git-workflow-merge.
6
6
  ---
7
7
 
8
8
  # Стопка заявок из одного основания
@@ -11,12 +11,70 @@ description: Паттерн правила git-workflow. Брать, когда
11
11
  `docs/constitution/delivery.md`. Разбор одного конфликта — паттерн `git-workflow-merge`,
12
12
  открытие одной заявки — `git-workflow-pr`.
13
13
 
14
+ **Вызовы здесь даны клиентом GitHub.** Дерево на другом хостинге читает их как форму, а команду
15
+ берёт у своего клиента: имена полей и подкоманд у клиентов разные, а спрашиваемое — одно.
16
+ Соответствие называет редакция правила поставки, разложенная в этом дереве.
17
+
14
18
  ## Когда брать
15
19
 
16
20
  - Из одного основания заведено больше двух веток, и все ждут слияния.
17
21
  - За заход сделано несколько работ, и они лежат в дереве невыложенными.
18
22
  - Решается, в каком порядке отдавать накопленное владельцу.
19
23
 
24
+ ## Череда: ветвиться от предыдущей, а не от главной
25
+
26
+ Стопка из одного основания — то, чего надо избежать. Работы, идущие подряд, ветвятся подряд:
27
+
28
+ ```bash
29
+ # первая работа череды — от главной, как обычно
30
+ git checkout -b <КЛЮЧ>-<номер>-<slug> origin/main
31
+
32
+ # каждая следующая — от предыдущей ветки, а не от origin/main
33
+ git checkout -b <КЛЮЧ>-<следующий>-<slug> <КЛЮЧ>-<номер>-<slug>
34
+ ```
35
+
36
+ Правка предыдущей лежит тогда в общем предке, и сводить два разных изменения одного файла не
37
+ приходится вовсе. Расхождение всплывает при ветвлении — у того, у кого обе правки свои и под
38
+ рукой, — а не при слиянии, у владельца, у которого нет ни одной.
39
+
40
+ От главной ветвится первая работа череды и всякая, которая предыдущей не касается: череда — это
41
+ про соседние работы, а не про все подряд.
42
+
43
+ ## Заявка череды стоит на предыдущей ветке
44
+
45
+ ```bash
46
+ gh pr create --base <предыдущая ветка> --title '[<КЛЮЧ>-<номер>] <что сделано>' --body-file <файл>
47
+ ```
48
+
49
+ Основанием главная не ставится: разбор тогда показывает свою правку вперемешку со всем, что под
50
+ ней. Влитую нижнюю хостинг переносит сам — базой её заявки-наследницы становится главная.
51
+
52
+ Порядок вливания стоит в теле каждой заявки строкой «стоит на #<номер>, вливать после него»:
53
+ владелец вливает по списку, а родство веток по списку не видно.
54
+
55
+ **Конвейер дерева проверяется на то, слушает ли он заявку с таким основанием.** Событие заявки
56
+ хостинг шлёт с фильтром по базе, и дерево, оставившее в фильтре одну главную ветку, всей череде
57
+ прогонов не даёт вовсе: заявка стоит зелёно-пустой, а вернуть событие нечем — ни новый коммит,
58
+ ни перезакрытие заявки базы не меняют. Спрашивается это до того, как череду заводить: у
59
+ настройки конвейера, а не у страницы заявки, где отсутствие прогона выглядит так же, как его
60
+ ожидание.
61
+
62
+ ```bash
63
+ # порядок череды целиком — снизу вверх
64
+ gh pr list --state open --json number,headRefName,baseRefName \
65
+ --jq '.[] | "\(.number)\t\(.headRefName)\tна \(.baseRefName)"'
66
+ ```
67
+
68
+ ## Чего в череде не делают
69
+
70
+ - **Историю нижней ветки не переписывают.** Ни `rebase`, ни силовая отправка: вершина верхней
71
+ становится достижимой из её основания, и хостинг закрывает заявку верхней как слитую — при том
72
+ что в главной её правок нет. Отставшая нижняя чинится вливанием главной в неё и дальше вверх.
73
+ - **Череду не вливают из середины.** Влитая не по порядку тащит за собой всё, что под ней, — и
74
+ разбор той работы уже не состоится.
75
+ - **Готовые ветки не копят.** Череда не отменяет того, что единица работы — влитая заявка: она
76
+ лишь делает безопасной ту длину, которая всё же накопилась.
77
+
20
78
  ## Единица работы — влитая заявка, а не открытая
21
79
 
22
80
  Открытый черновик работой не является: кнопка слияния у него заблокирована, в главной ветке его
@@ -65,6 +123,21 @@ docs/archive/README.md merge=union
65
123
  Сложение ставится только на указатели, где правка всегда добавляющая. На текст, который
66
124
  переписывают, оно оставит в файле обе редакции.
67
125
 
126
+ **Сложение сторон метку сливаемости не снимает, и вливать главную по ней нельзя.** Хостинг
127
+ считает сливаемость своим приёмом и настроек слияния не читает: ветка, тронувшая сложенный
128
+ указатель, помечается конфликтующей всё равно. Спрошенная у него стопка отвечает «конфликтует»
129
+ целиком, и вливание по этому ответу — то же вливание во все ветки, что и без сложения: раздел
130
+ ниже велит вливать главную по факту конфликта, а факт этот хостинг называет про каждую ветку
131
+ стопки. Пятнадцать заявок разом простояли так за один заход. Проверяется одной командой: то же
132
+ слияние без драйвера даёт конфликтный маркер, с драйвером идёт чисто — значит метку держит
133
+ указатель, а не правка.
134
+
135
+ **Указатель, куда дописывает каждая ветка стопки, из стопки убирается, а не складывается.**
136
+ Сложение — починка проявления: конфликта нет, метка есть, вливать по-прежнему приходится.
137
+ Спрашивается это до заведения веток: отвечает ли указатель на вопрос, которого не закрывает
138
+ обход каталога. Не отвечает — он снимается, и площадь пересечения стопки падает до настоящих
139
+ общих файлов.
140
+
68
141
  ## Порядок вливания задаётся заранее и называется владельцу
69
142
 
70
143
  Порядок считается до открытия заявок — по тому, кто какие файлы правит:
@@ -79,6 +152,25 @@ done | sort | uniq -c | sort -rn | head
79
152
  конфликт там, где подряд его бы не было. Порядок называется владельцу в теле заявки — кнопки
80
153
  нажимает он, а о родстве веток не знает.
81
154
 
155
+ ## Волна веток проверяется пробным слиянием
156
+
157
+ Ветка, лежащая невлитой рядом с соседками, зелена сама по себе: линт, тесты, сборки и сверки
158
+ она проходит одна. Сталкивается она с ними тем, чего на отдельной ветке не видит ни одна
159
+ проверка — тот же следующий свободный номер сценария, тот же заведённый новым файл, та же
160
+ правленная строка отметки. После слияния первые два чинятся уже в главной и стоят отдельной
161
+ работы.
162
+
163
+ ```bash
164
+ git fetch origin
165
+ git checkout -b probe-merge origin/main
166
+ for b in <ветка-1> <ветка-2> <ветка-3>; do git merge --no-edit "origin/$b" || break; done
167
+ npm run check:all
168
+ git checkout - && git branch -D probe-merge
169
+ ```
170
+
171
+ Ветка пробы удаляется, а находки и порядок слияния записываются туда, где живёт замысел линии
172
+ работ: пробное слияние отвечает на «что столкнётся», а не заменяет собой отдачу.
173
+
82
174
  ## Частые промахи
83
175
 
84
176
  - Открыты все заявки разом, потому что ветки были готовы. Готовность ветки признаком того, что
@@ -77,6 +77,10 @@ grep -rn "@<область>/<семья>/<домен>" libs/ apps/ | sed 's/:.*/
77
77
  npx nx run-many -t lint --projects=<список по изменённым файлам>
78
78
  ```
79
79
 
80
+ Этот прогон — быстрый, по горячим следам переноса, и набором перед пушем он не бывает:
81
+ набор, собранный по изменённым файлам, пропускает то, до чего правка дошла связями. Перед
82
+ пушем идёт тот же набор, что гоняет конвейер, и теми же командами.
83
+
80
84
  ## Проверить
81
85
 
82
86
  ```bash
@@ -33,6 +33,11 @@ docs/specs/<домен>/
33
33
  та же связь сценариев с тестами. Домен, у которого половина поддоменов описана, а половина
34
34
  заведена пустыми каталогами, зелёным не бывает.
35
35
 
36
+ Работа, задевшая домен и его поддомен, пишет две договорённости, а не одну. Префикс сценариев у
37
+ поддомена свой, а второго префикса одному спеку сверка не даёт: сценарии такой работы
38
+ разъезжаются по двум нумерациям — по одной на каждый спек, в который вольются. Замысел называет
39
+ обе, и вливаются они порознь, каждая в свой спек.
40
+
36
41
  ## Обязательные разделы
37
42
 
38
43
  `## Зачем` · `## Терминология` с подразделом `### Как это называется в интерфейсе` ·
@@ -49,6 +54,18 @@ docs/specs/<домен>/
49
54
  такой спек по строкам бесполезно, потому что делится в нём не описание домена, а ненаписанное
50
55
  правило.
51
56
 
57
+ **Заголовок записи раздела решений датой не называется.** Дата говорит, когда решение приняли, а
58
+ раздел отвечает на «почему так, а не иначе»: по дате решение не отобрать и не найти, зато
59
+ названная ею запись читается описанием прошлого и остаётся в спеке навсегда. Запись начинается с
60
+ самого решения.
61
+
62
+ **Утверждение, стоящее в другом разделе того же спека, вторым пунктом правил не заводится.**
63
+ Устройство записи живёт в разделе данных, порядок вызовов — в разделе контракта, причина
64
+ существования домена — в разделе «Зачем»: все три говорят о том же, о чём говорило бы правило.
65
+ Второй экземпляр расходится с первым молча, и заметить это нечем — сверка знает пункт правила
66
+ против якоря, а два утверждения об одном не сравнивает никто. Решение при этом из раздела решений
67
+ уезжает целиком: место, где требование живёт, найдено.
68
+
52
69
  Шапка несёт статус, дату ревизии, префикс сценариев, зависимости от других доменов, строку
53
70
  `**Законы:**` — законы, которые домен применяет, — и строку `**Процедуры:**` — корни либ, чьи
54
71
  процедуры домен обслуживает.
@@ -79,7 +96,7 @@ docs/specs/<домен>/
79
96
  ```
80
97
 
81
98
  Правило, которому места в коде не нашлось, — намерение: ему место в «Открытых вопросах» как
82
- `Q-N`, а не формальный якорь.
99
+ `Q-<буква закона>-<номер>`, а не формальный якорь.
83
100
 
84
101
  ## Сценарий
85
102
 
@@ -95,11 +112,17 @@ docs/specs/<домен>/
95
112
  `Не покрыто: <причина>`, сценарий с неполным тестом — `Покрытие: частичное — <чего не
96
113
  хватает>`.
97
114
 
115
+ Сценарий, который проверить нечем в принципе, не заводится вовсе. Пометка о непокрытом говорит
116
+ «теста ещё нет» и обещает, что он появится; там, где проверки не существует, обещания нет, а
117
+ помеченный сценарий висит в наборе вечно, читается как долг и заставляет каждого следующего
118
+ заново выяснять, не пора ли его закрыть. Правило, ради которого сценарий хотели завести,
119
+ остаётся правилом: его держат строка в компаньоне и запись в истории изменений, и этого довольно.
120
+
98
121
  Номер в идентификаторе живёт так:
99
122
 
100
123
  | Что случилось | Что делается с номером |
101
124
  | ----------------------- | ---------------------------------------------------------------------------------------------------- |
102
- | сценарий добавили | берётся следующий свободный — наибольший выданный в домене плюс один, а не дырка в середине |
125
+ | сценарий добавили | берётся следующий свободный — наибольший выданный **во всех ветках** плюс один, а не дырка в середине |
103
126
  | обещание изменили | номер тот же, заголовок теста правится тем же коммитом |
104
127
  | сценарий удалили | номер остаётся пустым и новому сценарию не отдаётся; тест удаляется вместе со сценарием |
105
128
  | номера захотелось сжать | не пересчитываются: связь с тестами держит только номер, а прогон остаётся зелёным при обеих правках |
@@ -107,6 +130,15 @@ docs/specs/<домен>/
107
130
  Номер записывается так же, как у соседей в этом же файле: сверка ищет его шаблоном, и номер,
108
131
  записанный иначе, не совпадёт ни в спеке, ни в заголовке теста.
109
132
 
133
+ **Свободный номер ищется во всех ветках, а не в одной главной.** Соседняя работа держит свои
134
+ номера на диске и в главную ещё не въехала: шесть номеров так раздали дважды, и двигаться
135
+ пришлось той работе, чья договорённость не влита. Номер — единственное, чем сценарий связан с
136
+ тестом, и отданный второй раз он оставляет старую ссылку правильной на вид и ведущей не туда.
137
+
138
+ Спрашивается это командой дерева, если дерево её завело: она читает заголовки сценариев во всех
139
+ ветках — своих и удалённых — и печатает первый свободный за наибольшим занятым. Имя команды
140
+ называет компаньон правила.
141
+
110
142
  ## Порядок работы
111
143
 
112
144
  1. Задача заводится сценариями: что станет верно, когда работа закончится.
@@ -115,6 +147,10 @@ docs/specs/<домен>/
115
147
  4. `npm run check:specs` — до пуша.
116
148
  5. Приёмка идёт по сценариям, а не по пересказу правки.
117
149
 
150
+ Правило, обещающее человеку видимый результат, подтверждается на работающем приложении, а не
151
+ выводом из графа вызовов. Чтением подтверждаются заголовки, связь с привязками и форма данных;
152
+ правило, которое подтвердить не на чем, уезжает открытым вопросом и утверждением не пишется.
153
+
118
154
  ## Частые промахи
119
155
 
120
156
  - Выросший домен делят на новые домены, а не на поддомены: новый домен приходится заводить в
@@ -139,10 +175,19 @@ docs/specs/<домен>/
139
175
  - Закон, названный в тексте, но забытый в строке `**Законы:**`: по закону тогда не узнать,
140
176
  какие домены на нём стоят.
141
177
  - Правка `.proto` без спеков задетых доменов: `docs-guard` отбивает такой коммит.
178
+ - **Правило, выведенное из графа вызовов, ошибается беззвучно.** Читается оно так же уверенно,
179
+ как замеренное, и сверка привязки его пропускает — символ на месте, просто описывает он не то.
180
+ Два правила одного спека оказались перевёрнутыми: связь шла не между хранилищами, а через
181
+ слушающий их компонент, — и оба чуть не стали задачей на дефект, которого нет.
182
+
142
183
  - **Выросший домен делится на поддомены, а не на новые домены.** Новый домен пришлось бы
143
184
  заводить в указателе, сверять с кодом отдельно и объяснять, чем он соседу не поддомен;
144
185
  поддомен остаётся в своём домене и наследует его контракт. Соседний домен заводится только
145
186
  тогда, когда предмет живёт своей сущностью.
187
+ - **Наибольший выданный номер ищется по всему домену командой, а не глазами по хвосту файла.**
188
+ Номера в файле сценариев идут не по порядку: правки вставляли их к соседям по смыслу, и
189
+ последняя строка максимума не показывает. Шесть новых номеров из одиннадцати легли на занятые
190
+ — поймала это сверка спеков, а не чтение, и переписывать пришлось заодно заголовки тестов.
146
191
  - **Границу между доменами проводит владелец, а не автор очередной правки.** Автор видит свою
147
192
  правку, а не то, чем предмет обрастёт: домен, заведённый по ходу дела, через месяц оказывается
148
193
  половиной соседнего, и разводить их приходится вместе с номерами сценариев.
@@ -33,7 +33,10 @@ description: Паттерн правила spec-driven. Брать при зав
33
33
  вопрос есть, и стираются вместе с последним закрытым: закрытый вопрос из закона убирается, а
34
34
  не превращается в пустой раздел.
35
35
 
36
- Ни истории правок, ни доводов о том, почему когда-то выбрали так, в законе нет. Историю
36
+ Даты в законе тоже нет: у одного закона из семнадцати она стояла, у остальных не появлялась
37
+ никогда, а прочитанная как срок годности — старит верный текст, которого никто не трогал, потому
38
+ что трогать было нечего. Ни истории правок, ни доводов о том, почему когда-то выбрали так, в
39
+ законе нет. Историю
37
40
  держит система контроля версий, а довод с отвергнутой альтернативой — свойство работы, а не
38
41
  продукта: ему место в «Ловушках» правила под этим законом, где и путям к файлам можно.
39
42
  Утверждение, которое нельзя написать как «верно всегда», статьёй не становится вовсе.
@@ -43,8 +46,6 @@ description: Паттерн правила spec-driven. Брать при зав
43
46
 
44
47
  Как правка доезжает до работающего приложения. …
45
48
 
46
- **Ревизия:** 2026-08-05
47
-
48
49
  ## Статьи
49
50
 
50
51
  - **Выкатывается образ того коммита, который выкатывают.** Умолчание «последний» отстаёт от
@@ -74,6 +75,17 @@ description: Правило под «Закон о поставке». Брат
74
75
  ---
75
76
  ```
76
77
 
78
+ Под шапкой стоит строка требования к соседним ресурсам — тем, без которых статьи правила не
79
+ исполняются:
80
+
81
+ ```markdown
82
+ **Требует:** `hooks/<гард>.sh`, `checks/<проверка>.mjs`
83
+ ```
84
+
85
+ Ресурсы называются именами пакета, а не путями дерева. Строки нет — правило не требует ничего;
86
+ пустой она не бывает. Выводить требование из фразы в тексте нельзя: разложено у потребителя не
87
+ всё, и текст, сказавший «правку отбивает гард», врёт в дереве, где гарда нет.
88
+
77
89
  Разделы: `## Как это называется здесь` · `## Где это лежит` · `## Как закон применяется
78
90
  здесь` · `## Чего из закона здесь нет` · `## Паттерны` · `## Ловушки`.
79
91
 
@@ -87,7 +99,7 @@ description: Правило под «Закон о поставке». Брат
87
99
  ```
88
100
 
89
101
  Утверждение, которому места в коде не нашлось, в этот раздел не ставится: оно уходит прозой в
90
- «Ловушки» или вопросом `Q-N` в закон.
102
+ «Ловушки» или вопросом `Q-<буква закона>-<номер>` в закон.
91
103
 
92
104
  ## Паттерн
93
105
 
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: spec-driven-sweep
3
+ kind: pattern
4
+ rule: spec-driven
5
+ description: Паттерн правила spec-driven. Брать при сплошном разборе привязки домена — пять проходов, три из которых делает машина, разбор срабатываний чтением и доля ложных по слоям. Не брать для заведения спека домена — это паттерн spec-driven-domain.
6
+ ---
7
+
8
+ # Сплошной разбор привязки домена
9
+
10
+ Паттерн правила `spec-driven`. Что при этом должно быть верно — закон о документации проекта.
11
+
12
+ ## Когда брать
13
+
14
+ - Привязка домена разбирается целиком: каждое утверждение против кода, на который оно указывает.
15
+ - Тексты дерева сверяются с деревом задачей, а не по ходу другой работы.
16
+
17
+ ## Проходов пять, и порядок у них один
18
+
19
+ Три первых делает машина по всему домену разом, два последних — чтение. Порядок не
20
+ переставляется: чтение идёт по строкам, которые машина уже отобрала, иначе читается весь домен.
21
+
22
+ 1. **Мёртвый адрес.** Названного файла нет в дереве, или символа нет нигде. Даёт ноль на домене,
23
+ который уже разбирали, и целую пачку на том, откуда недавно уезжал код.
24
+ 2. **Якорь, живущий только в пояснении.** Символ встречается в дереве лишь в комментариях.
25
+ Проверка привязки комментарий засчитывает наравне с кодом, поэтому такому якорю она зелёная, а
26
+ места исполнения за ним нет.
27
+ 3. **Символ не объявлен в названном файле.** Файл его импортирует и зовёт, а объявление лежит в
28
+ другом месте. Самый урожайный проход и самый шумный.
29
+ 4. **Обещание против кода.** Читается код по адресу: делает ли он то, что утверждает правило.
30
+ Машине этот проход не даётся вовсе — расхождение здесь обычно в условии и в порядке шагов.
31
+ 5. **Число, код отказа и ключ словаря — поимённо.** Каждое число из текста ищется в дереве,
32
+ каждый названный код отказа — в месте, где он бросается, каждый ключ словаря — во всех
33
+ локалях. Расхождение тут выглядит опечаткой и живёт годами.
34
+
35
+ ## Срабатывание — очередь на чтение, а не список дефектов
36
+
37
+ Проход выдаёт строки, находкой становится подтверждённая чтением. Разница не словесная: строки
38
+ третьего прохода на треть законны у любого домена, и записанные находками они превращают разбор в
39
+ правку верного кода. В ход работы идут оба числа — сколько строк дал проход и сколько из них
40
+ оказались расхождениями.
41
+
42
+ ## Доля ложных зависит от слоя
43
+
44
+ Там, где правило живёт в процедуре, место исполнения одно и оно публично: срабатывание третьего
45
+ прохода чаще оказывается расхождением — из четырнадцати строк шесть. Там, где правило живёт в
46
+ компоненте или службе, местом исполнения законно бывает приватное поле или приватный метод: из
47
+ тридцати шести строк расхождений не оказалось ни одной. Поэтому число находок прошлого домена на
48
+ следующий не переносится — переносится только сам порядок проходов.
49
+
50
+ ## Частые промахи
51
+
52
+ - **Урожайность прохода обещана фактом.** «Проход даст столько-то» — оценка, и по чужому слою она
53
+ промахивается целиком. Разбор просьбы называет проходы, а не число находок.
54
+ - **Проход, давший ноль, не записан.** Следующий заход гоняет его заново по тому же домену. Ноль
55
+ — такой же результат, и он пишется вместе с остальными.
56
+ - **Счёт сторон принят за разбор.** Зелёная проверка привязки говорит, что у каждого утверждения
57
+ есть строка, а куда эта строка ведёт — не говорит ничего.
@@ -57,7 +57,7 @@ gh api repos/:owner/:repo/issues/<номер> --jq '{t:.title,s:.state,labels:[.
57
57
  имя команды в оболочке бывает занято чужим псевдонимом, и тогда вызов уходит в интерактивный
58
58
  вход вместо ответа.
59
59
 
60
- ## Ловушки
60
+ ## Частые промахи
61
61
 
62
62
  - **Задача на борде читается запросом, а не подкомандой просмотра.** Подкоманда тянет за собой
63
63
  доски старого образца, хостинг отвечает отказом о них, и вызов краснеет целиком, ничего не
@@ -46,7 +46,17 @@ description: Паттерн правила task-flow. Брать, когда т
46
46
  | `grill.md` | в `docs/archive/` — ответы владельца невосстановимы, и это единственная запись о том, почему задача поставлена так |
47
47
  | `progress.md` | в `docs/archive/`, если в нём есть решения по ходу с причинами; иначе удаляется |
48
48
  | `plan.md` | удаляется — после выкатки на его вопрос отвечает код, а на «как работает» отвечает спек домена |
49
- | находки разбора | переезжают к замыслу эпика — их читает владелец, когда эпик кончится; работа вне эпика показывает их сразу |
49
+ | находки разбора | пишутся сразу рядом с замыслом эпика — не переезжают отсюда; работа вне эпика показывает их владельцу тем же ходом |
50
+
51
+ Находки в папке задачи не живут вовсе. Разбор идёт фоном, и когда он кончится, не знает никто:
52
+ папка к этой минуте разобрана, а ветка бывает уже влита и снята. Оба срока назначает не
53
+ исполнитель, поэтому переезд «из папки к замыслу эпика» держался бы на совпадении, которого может
54
+ и не случиться. Тем же местом пользуется находка, замеченная не разбором, а по ходу работы.
55
+
56
+ Находки, вернувшиеся после того, как ветка ушла, едут веткой следующей задачи: пуш в снятую ветку
57
+ её не обновляет, а заводит заново, и коммит остаётся вне главной. Следующая задача к этой минуте
58
+ уже взята — её веткой уборка за предыдущей и едет, тем же порядком, каким разбирают чужую папку
59
+ задачи. Эпик кончился и следующей задачи нет — находки уезжают своей задачей.
50
60
 
51
61
  Уезжающее складывается одним файлом с говорящим именем, а не папкой из трёх:
52
62
 
@@ -117,18 +127,50 @@ npm run check:docs # пути, названные в текстах, суще
117
127
  3. **Вернувшиеся находки принимают одним ходом** — записать и вернуться к прежнему. Разбор,
118
128
  отложенный «до удобного момента», не случается вовсе: заход кончается раньше.
119
129
 
120
- **Следующее движение:** пока роль разбирает, тот же ход занят следующей задачей; вернувшиеся
121
- находки принимаются одним ходом — записать и продолжить прежнее.
130
+ ### Записи груза переводятся в «готово» тем же ходом
131
+
132
+ Работа, начатая с приехавшего груза, кончается здесь, а не на разборе папки: до слияния правки в
133
+ дереве нет, и отметка утверждала бы то, чего в главной ветке ещё не лежит. Это единственное
134
+ состояние, где слияние уже случилось, а ход о задаче ещё идёт.
135
+
136
+ Ключи берутся из описания прошлого — папки задачи на диске к этой минуте нет, — и подставляются
137
+ полными, как их печатает чтение приёма:
138
+
139
+ ```bash
140
+ npm run cargo:mark -- --state fixed \
141
+ --proposal <полный ключ> --proposal <полный ключ> \
142
+ --fix '<чем исправлено: статья правила, гард, проверка, правка кода>'
143
+ ```
144
+
145
+ Приём починки один на вызов, поэтому записи едут пачками по тому, чем закрыты, а не всей задачей
146
+ разом. Ответ читается: «переведено 0» означает, что этот разбор не двинул ничего.
147
+
148
+ **Следующее движение:** пока роль разбирает, тот же ход занят следующей задачей; записи груза
149
+ переводятся в «готово» этим же ходом, вернувшиеся находки принимаются одним ходом — записать и
150
+ продолжить прежнее, а владельцу о них говорится, когда кончился эпик.
122
151
 
123
- ## Состояние `влито`: находки разбора ложатся в папку задачи и ждут владельца
152
+ ## Находки разбора ложатся к замыслу эпика и ждут владельца
124
153
 
125
- Ответ роли живёт в переписке и умирает вместе с ней, поэтому он сразу ложится на диск — в папку
126
- задачи, файлом рядом с ходом работы. Пишет его исполнитель: роль файлов не пишет.
154
+ Ответ роли живёт в переписке и умирает вместе с ней, поэтому он сразу ложится на диск. Пишет
155
+ его исполнитель: роль файлов не пишет.
127
156
 
128
- Папка задачи умирает со слиянием, а находки должны пережить весь эпик владелец читает их
129
- разом, когда эпик кончился. Поэтому при разборе папки файл находок не удаляется вместе
130
- с остальным, а **переезжает к замыслу эпика**: там его найдут и после того, как ветка въехала.
131
- Работа вне эпика показывает находки владельцу сразу, тем же ходом.
157
+ **Пишутся находки сразу в файл рядом с замыслом эпика, а не в папку задачи.** Разбор идёт
158
+ фоном, и когда он кончится, не знает никто; папка задачи к этому времени бывает уже разобрана,
159
+ а ветка влита и снята. Оба срока назначает не исполнитель, поэтому переезд «из папки к замыслу
160
+ эпика» держится на совпадении, которого может и не случиться. Тем же местом пользуется находка,
161
+ замеченная не разбором, а по ходу работы. Работа вне эпика показывает находки владельцу тем же
162
+ ходом.
163
+
164
+ **Находки, вернувшиеся после того, как ветка ушла, едут веткой следующей задачи.** Пуш в снятую
165
+ ветку её не обновляет, а заводит заново: коммит остаётся вне главной ветки и пропадает вместе
166
+ с ней. Следующая задача к этому времени уже взята — её веткой уборка за предыдущей и едет.
167
+ Эпик кончился и следующей задачи нет — находки уезжают своей задачей.
168
+
169
+ **Накопительный файл находок делится до дописи, а не после.** Длина смотрится одной командой
170
+ перед первой написанной строкой: раздел задачи занимает десятки строк, и предел длины документа
171
+ он переходит молча. Гейт пуша показывает превышение, когда допись уже закоммичена, — тогда
172
+ деление идёт задним числом, вместе с правкой ссылок на файл. Не влезает — заводится следующая
173
+ часть, и раздел пишется сразу в неё.
132
174
 
133
175
  **Наружу без слова владельца уезжает только сводка наблюдений.** Она говорит, чем пользовались
134
176
  и чем не пользовались ни разу, — это факт, и мнением он не станет. Предложение — другое дело:
@@ -155,18 +197,18 @@ npm run check:docs # пути, названные в текстах, суще
155
197
  котором владелец сказал вслух, уходит наружу в тот же ход: написанное и не отправленное лежит в
156
198
  дереве неотличимо от отправленного.
157
199
 
158
- **Следующее движение:** записанные находки работу не держат — следующая задача уже идёт, а
159
- владельцу о них говорится, когда кончился эпик.
160
-
161
- ## Ловушки
200
+ ## Частые промахи
162
201
 
163
202
  - **Папку разбирают до открытия заявки — потом о ней уже никто не вспомнит.** Сверка очереди
164
203
  считает задачу закрытой по слиянию: после него за папку никто не отвечает — работа перешла к
165
204
  следующей задаче, и находка достанется чужому заходу. Держит это гард поставки:
166
205
  открытие заявки отбивается, пока папка лежит в ветке.
167
206
  - **Разбор папки идёт последним коммитом, после того как гейт пуша прошёл целиком.** Порядок
168
- один: мерж главной ветки, все линтеры и проверки зелёные, вливание договорённости, приведение
169
- текстов домена, разбор папки — и только потом заявка.
207
+ один: мерж главной ветки, вливание договорённости, приведение текстов домена, все линтеры и
208
+ проверки зелёные, разбор папки — и только потом заявка. Дешёвый шаг стоит раньше дорогого:
209
+ заход, потративший окно на прогон, упирался в порог заполнения на четырёх строках привязки, и
210
+ дописать их было уже нечем. Второй довод сильнее: прогон, стоящий после вливания, проверяет и
211
+ само вливание — иначе он смотрит то состояние дерева, которое в главную ветку не поедет.
170
212
  - **После разбора замысла на диске нет, и собирать папку заново не надо.** Правку по замечаниям
171
213
  разбора и починку красного прогона гард хода работы пропускает по признаку из истории ветки:
172
214
  папка, снятая её коммитом, и есть признак отданной работы. Собранная заново папка вернула бы