@rt-tools/agent-kit 0.16.0 → 0.17.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/board-paths.github.mjs +88 -0
- package/assets/checks/board-runs.github.mjs +8 -0
- package/assets/checks/board-titles.github.mjs +66 -0
- package/assets/checks/check-board.github.mjs +17 -4
- package/assets/checks/check-file-size.mjs +10 -2
- package/assets/checks/check-glossary.mjs +170 -0
- package/assets/checks/check-push-gate.mjs +59 -1
- package/assets/checks/check-schema-drift.mjs +12 -5
- package/assets/checks/spec-contract.mjs +9 -0
- package/assets/defaults/gate-map.sh +13 -4
- package/assets/defaults/project.sh +22 -3
- package/assets/docs/GLOSSARY.md +1 -1
- package/assets/hooks/browser-device-id.sh +20 -4
- package/assets/hooks/browser-guard-device-id.sh +5 -2
- package/assets/hooks/git-guard-delivery-folder.sh +19 -0
- package/assets/hooks/git-guard-delivery.sh +39 -0
- package/assets/hooks/git-guard-push-tests.sh +21 -1
- package/assets/hooks/grill-gate-ask.sh +25 -0
- package/assets/hooks/grill-gate.sh +12 -5
- package/assets/hooks/lint-after-edit.sh +44 -16
- package/assets/hooks/proposal-guard.sh +17 -1
- package/assets/hooks/skill-gate-layers.sh +7 -0
- package/assets/hooks/skill-gate.sh +29 -0
- package/assets/hooks/task-context-load.sh +10 -0
- package/assets/hooks/task-flow-context.sh +185 -0
- package/assets/hooks/task-flow-draft-guard.sh +92 -0
- package/assets/hooks/task-flow-guard.sh +27 -159
- package/assets/hooks/turn-exit-guard.sh +8 -1
- package/assets/hooks/window-fill-guard.sh +5 -1
- package/assets/laws/delivery.md +19 -0
- package/assets/laws/frontend-application.md +4 -0
- package/assets/laws/verifiability.md +21 -0
- package/assets/laws/work-conduct.md +15 -0
- package/assets/patterns/browser-verification-stand.md +7 -2
- package/assets/patterns/doc-style-write.md +41 -1
- package/assets/patterns/git-workflow-commit.github.md +15 -2
- package/assets/patterns/git-workflow-docker.md +14 -0
- package/assets/patterns/git-workflow-merge.md +18 -0
- package/assets/patterns/git-workflow-migration.md +11 -0
- package/assets/patterns/git-workflow-pr.github.md +6 -1
- package/assets/patterns/git-workflow-secrets.md +14 -0
- package/assets/patterns/git-workflow-stack.md +63 -1
- package/assets/patterns/spec-driven-domain.md +34 -1
- package/assets/patterns/spec-driven-rule.md +11 -0
- package/assets/patterns/spec-driven-sweep.md +57 -0
- package/assets/patterns/task-flow-archive.md +46 -14
- package/assets/patterns/task-flow-close.md +78 -2
- package/assets/patterns/task-flow-resume.md +17 -5
- package/assets/patterns/task-flow-start.md +42 -4
- package/assets/pitfalls/agent-kit.md +73 -3
- package/assets/pitfalls/doc-style.md +5 -0
- package/assets/pitfalls/git-workflow.github.md +68 -0
- package/assets/pitfalls/spec-driven.md +16 -0
- package/assets/pitfalls/task-flow.md +93 -0
- package/assets/pitfalls/turn-conduct.md +14 -0
- package/assets/rules/browser-verification.md +39 -0
- package/assets/rules/deploy-flow.azure.md +8 -0
- package/assets/rules/deploy-flow.github.md +18 -0
- package/assets/rules/deploy-flow.gitlab.md +8 -0
- package/assets/rules/doc-style.md +14 -0
- package/assets/rules/git-workflow.azure.md +5 -0
- package/assets/rules/git-workflow.github.md +85 -75
- package/assets/rules/git-workflow.gitlab.md +5 -0
- package/assets/rules/reuse-first.md +8 -0
- package/assets/rules/shared-code.md +5 -0
- package/assets/rules/spec-driven.md +14 -0
- package/assets/rules/task-flow.md +112 -112
- package/assets/rules/testing.md +14 -1
- package/assets/rules/turn-conduct.md +40 -27
- package/assets/rules/turn-entry.md +6 -0
- package/assets/samples/tasks/_template/grill.md +5 -0
- package/assets/samples/tasks/_template/plan.md +3 -0
- package/assets/skills/agent-kit.md +99 -76
- package/assets/templates/postmortem.md +5 -1
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +30 -6
- package/bin/agent-kit.js.map +1 -1
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +2 -1
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +96 -7
- package/lib/commands.js.map +1 -1
- package/lib/hooks-map.d.ts +26 -0
- package/lib/hooks-map.d.ts.map +1 -1
- package/lib/hooks-map.js +58 -2
- package/lib/hooks-map.js.map +1 -1
- package/lib/sections.d.ts +6 -0
- package/lib/sections.d.ts.map +1 -1
- package/lib/sections.js +19 -0
- package/lib/sections.js.map +1 -1
- package/lib/shipment.d.ts +2 -0
- package/lib/shipment.d.ts.map +1 -1
- package/lib/shipment.fixture.d.ts +5 -0
- package/lib/shipment.fixture.d.ts.map +1 -1
- package/lib/shipment.fixture.js +7 -0
- package/lib/shipment.fixture.js.map +1 -1
- package/lib/shipment.js +13 -1
- package/lib/shipment.js.map +1 -1
- package/lib/sync.d.ts +35 -3
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +59 -8
- package/lib/sync.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.17.0.tgz +0 -0
- package/rt-tools-agent-kit-0.16.0.tgz +0 -0
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
человек его видит, лежит всё, чего проверка не касалась.
|
|
17
17
|
- **Тест, выключенный признаком окружения, покрытием не считается.** В обычном прогоне он не
|
|
18
18
|
исполняется ни разу, а в сводке выглядит так же, как исполненный.
|
|
19
|
+
- **Тест, снимающий себя по тому, что застал на экране, покрытием не считается.** Набор, идущий
|
|
20
|
+
одной сессией, несёт состояние из теста в тест, и проверка, начинающаяся с «нужного на экране
|
|
21
|
+
нет — пропускаю», снимает себя от чужой правки, а не от своего окружения. В сводке это одна
|
|
22
|
+
строка про пропуск, а стоит за ней целая возможность.
|
|
23
|
+
- **Тест приводит экран в нужное ему состояние сам и возвращает общее состояние таким, каким
|
|
24
|
+
застал.** Иначе снявшийся тест держится ровно до следующей правки соседа, а прогон называет
|
|
25
|
+
ноль падений и в тот день, когда проверка не исполнялась ни разу.
|
|
26
|
+
- **Проговорённый список проверок проверкой не бывает.** Он называет замысел, а не то, что
|
|
27
|
+
ушло в команду, и оба текста пишутся одним ходом, не сверяясь друг с другом: список, названный
|
|
28
|
+
пункт за пунктом, от короткого «я проверил» отличается только длиной. Проверка — чтение
|
|
29
|
+
полученного: вывода команды, отданного текста, состояния после вызова.
|
|
19
30
|
- **Упоминание в тесте сценария, которого нет, — отказ.** Так ловится переименованный или
|
|
20
31
|
выкинутый сценарий: без этого он пропадает молча.
|
|
21
32
|
- **Работающее приложение проверяется там, где его видит пользователь.** Отладочный режим ведёт
|
|
@@ -37,6 +48,16 @@
|
|
|
37
48
|
Сообщение о готовности говорит лишь, что служба себя объявила: та, которой не досталось ни
|
|
38
49
|
одного задания, выглядит в нём точно так же, как работающая. Проверяются обе стороны связи — что
|
|
39
50
|
заказчик выбирает именно её и что задание через неё прошло.
|
|
51
|
+
- **У обмена спрашивают обе стороны, и сторона, которой нет, называется прямо.** Односторонний
|
|
52
|
+
обмен выглядит рабочим с обеих сторон: отправляющая получает успех на каждый вызов, а того, что
|
|
53
|
+
прочитать результат нечем, не видно ниоткуда — молчание об отсутствующей стороне неотличимо от
|
|
54
|
+
работающего обмена. Поэтому у обмена спрашивают не «прошёл ли вызов», а «читает ли кто-нибудь
|
|
55
|
+
вторую сторону», и ответ «нечем» записывается словом, а не остаётся пробелом.
|
|
56
|
+
- **Значение, объявленное одной стороной обмена, второй не пересчитывается, а берётся у первой.**
|
|
57
|
+
Две копии одного счёта расходятся молча, и обе стороны при этом отвечают успехом: одна шлёт под
|
|
58
|
+
одним значением, другая ищет под другим, и не находит ничего ни разу. Что именно объявлено —
|
|
59
|
+
признак, форма записи, способ счёта ключа — берётся у объявившей стороны целиком, а не
|
|
60
|
+
повторяется по её описанию.
|
|
40
61
|
- **Причина отказа, на которой строится решение, подтверждается измерением, а не правдоподобием.**
|
|
41
62
|
Объяснение, пришедшее первым, объясняет наблюдаемое не хуже верного: свойство среды и
|
|
42
63
|
собственный промах выглядят в отказе одинаково, и разводит их только замер, поставленный так,
|
|
@@ -41,6 +41,15 @@
|
|
|
41
41
|
принимается заново.** Отменённое решение следа в работе не оставляет — по результату не видно ни
|
|
42
42
|
того, что его принимали, ни того, что от него отказались. Принятое заново оно расходится с
|
|
43
43
|
прежним молча и стоит той же работы второй раз.
|
|
44
|
+
- **Решение, которое переживёт задачу, записывается там, где оно переживёт.** Ход работы умирает
|
|
45
|
+
вместе с папкой задачи, а имя, адрес и выбранный способ, названные владельцем посреди серии
|
|
46
|
+
работ, нужны следующим её задачам. Не переехавшее решение существует только в переписке того
|
|
47
|
+
захода, в котором принято: следующий заход делает разведку честно, не находит ничего — и
|
|
48
|
+
задаёт владельцу вопрос, на который тот уже отвечал.
|
|
49
|
+
- **Инструмент, названный в просьбе, входит в просьбу.** Замена его на свой — отступление от
|
|
50
|
+
просьбы, даже когда свой даёт тот же ответ: равноценность инструментов решает тот, кто просит.
|
|
51
|
+
Одинаковый результат равноценностью не является — у названного инструмента бывает видно то,
|
|
52
|
+
чего у заменителя нет вовсе.
|
|
44
53
|
- **Понимание записано там, где идёт работа.** Оставленное в переписке живёт у одного участника и
|
|
45
54
|
до следующего дня; работу продолжает тот, у кого этой переписки нет.
|
|
46
55
|
- **Сказанное владельцем записывается его словами и задним числом не переписывается.** Пересказ
|
|
@@ -197,6 +206,12 @@
|
|
|
197
206
|
- **Уборка за работой идёт до того, как о готовности сказано.** Всё, что работа обязана убрать за
|
|
198
207
|
собой, убирается раньше просьбы включить её в общее дерево, а не после согласия. После включения
|
|
199
208
|
убирать уже некому: работа перешла к следующей задаче.
|
|
209
|
+
- **Постоянное указание среды исполнения слабее правила дерева.** Среда описывает своё
|
|
210
|
+
умолчание и о дереве не знает; дерево вправе его отменить и отменяет молча — тем, что говорит
|
|
211
|
+
иначе. Расхождение разрешается в пользу дерева, а не того из двух текстов, который строже
|
|
212
|
+
сформулирован или ближе стоит к делу. Опознаётся оно чтением обоих, а не проверкой: указание
|
|
213
|
+
среды приходит в заход текстом, и сличить его с правилом машине не по чему.
|
|
214
|
+
|
|
200
215
|
- **Пока эпик не кончился, следующая работа не выбирается, а берётся.** Выбор, предложенный
|
|
201
216
|
владельцу при назначенном порядке, — это просьба назначить его заново: он уже назначен, и
|
|
202
217
|
предлагать его повторно значит отменять собственное планирование.
|
|
@@ -40,6 +40,10 @@ PORT={{prodSitePort}} node dist/apps/site/server/server.mjs
|
|
|
40
40
|
Это не дев-сервер: гард ловит `nx|ng serve`, пакетные раннеры и статические серверы, а запуск
|
|
41
41
|
собранного сервера пропускает.
|
|
42
42
|
|
|
43
|
+
Поведение, зависящее от хоста — адрес владельца, увод, разный ответ на разных именах, —
|
|
44
|
+
проверяется прямо здесь одним запросом с заданным заголовком. Прокси с подменой для этого не
|
|
45
|
+
нужен: он добавляет ещё один процесс, чьё поведение придётся отделять от проверяемого.
|
|
46
|
+
|
|
43
47
|
## Стенд админки
|
|
44
48
|
|
|
45
49
|
```bash
|
|
@@ -107,8 +111,9 @@ docker run -d --name <префикс>-stand-nginx \
|
|
|
107
111
|
`nginx.conf`, — файл с расширением `.conf` в смонтированном каталоге попал бы в `include`
|
|
108
112
|
и уронил бы nginx на директиве `user`. Без него стенд поднимается на конфиге образа, и
|
|
109
113
|
предел соединений на воркер там свой.
|
|
110
|
-
-
|
|
111
|
-
|
|
114
|
+
- Чужой `Host` отбивает **дев-сервер**, а не собранное приложение: прод-сборка отвечает на него
|
|
115
|
+
тем же, чем и на свой. За настоящим прокси запросы идут со своим заголовком ровно потому, что
|
|
116
|
+
прокси стоит перед дев-сервером, — оттуда и `-H "Host: localhost"`.
|
|
112
117
|
- Переменные окружения стенда обязаны смотреть на процессы стенда. `CACHE_REFRESH_URL`,
|
|
113
118
|
направленный на {{sitePort}}, сбрасывает кэш мимо того процесса, который держит справочник
|
|
114
119
|
перенаправлений в памяти, — исправный механизм при этом выглядит сломанным.
|
|
@@ -69,7 +69,20 @@ description: Паттерн правила doc-style. Брать при напи
|
|
|
69
69
|
✓ у пустого списка должен быть текст, у отказа — кнопка повтора
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Проверка: прочитать фразу вслух. Если так не говорят — переписать.
|
|
72
|
+
Проверка: прочитать фразу вслух. Если так не говорят — переписать. Слухом это ловится в той
|
|
73
|
+
фразе, которую читают, и не ловится в файле на восемьсот строк: оборот всплывает по всему
|
|
74
|
+
тексту, и глазами он не считается.
|
|
75
|
+
|
|
76
|
+
Вторая половина проверки — счёт, и там, где дерево разложило проверку слога
|
|
77
|
+
`checks/check-prose-style.mjs`, набор оборотов накоплен в ней самой: каждый признак назван
|
|
78
|
+
вместе с заменой, а находка печатается файлом и строкой. Оборот, найденный вычиткой,
|
|
79
|
+
дописывается в набор тем же ходом — иначе следующий пишущий начинает с пустого места и
|
|
80
|
+
собирает его заново из своей памяти.
|
|
81
|
+
|
|
82
|
+
Чего не видит ни слух, ни она: повтора законного оборота. Каждое его появление законно
|
|
83
|
+
поодиночке, а стоящий в тексте десятками он уже не приём, а тик — читатель перестаёт замечать
|
|
84
|
+
его вместе со смыслом. Считается это грепом по тексту, и число само по себе отказом не бывает:
|
|
85
|
+
судит его тот, кто правит следующим.
|
|
73
86
|
|
|
74
87
|
## Факт проверяется, а не вспоминается
|
|
75
88
|
|
|
@@ -79,6 +92,33 @@ description: Паттерн правила doc-style. Брать при напи
|
|
|
79
92
|
Особенно это касается отказов: «вернётся `value out of range`» продержалось в двух документах,
|
|
80
93
|
хотя такой отказ недостижим — в контракте и в колонке одна ширина.
|
|
81
94
|
|
|
95
|
+
**Утверждение о состоянии другой ветки читается из неё, а не из своей копии.** Копия, снятая при
|
|
96
|
+
отведении, отвечает на любой вопрос о содержимом файла и ни одним признаком не показывает,
|
|
97
|
+
насколько она отстала. Трижды за один заход состояние общей ветки вывели из файла на своей,
|
|
98
|
+
отставшей на семь коммитов; все три вывода неверны, один доехал до документа задачи и был назван
|
|
99
|
+
владельцу как факт. Поймано ребейзом, то есть случайно.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git fetch origin
|
|
103
|
+
git show origin/main:<путь к файлу>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Утверждение «все N таких-то» пишется после перечисления маршрутов, которыми значение попадает в
|
|
107
|
+
место, а не после скана по одному образцу.** Скан подтверждает ровно тот маршрут, который в него
|
|
108
|
+
заложен, и молчит обо всех прочих — тем увереннее, чем точнее образец. Посчитали места по образцу
|
|
109
|
+
самого вызова, получили 22 и записали в план и в описание заявки, что порядок держится
|
|
110
|
+
устройством; мимо прошли десять вызовов обёртки, которая берёт значение аргументом. Мест
|
|
111
|
+
оказалось 32, и у десяти значение стояло числом.
|
|
112
|
+
|
|
113
|
+
**Команда, которой получено число, проверяется на том, что она мерит спрошенное.** Вывод команды
|
|
114
|
+
— не подтверждение сам по себе: инструмент отвечает на тот вопрос, который понял, и о непонятой
|
|
115
|
+
части образца молчит. Три числа подряд за один заход: граница слова, не реализованная в этой
|
|
116
|
+
сборке инструмента и не объявленная отказом, дала 278 вхождений вместо 79; счёт вызовов
|
|
117
|
+
регулярным выражением дал 32 и 42 на одном и том же, а по синтаксическому дереву их 27.
|
|
118
|
+
|
|
119
|
+
**Число, пришедшее из прошлой сессии, замером не считается.** Оно неотличимо от замеренного и в
|
|
120
|
+
документе выглядит так же уверенно; пересчитывается заново тем же ходом, которым пишется.
|
|
121
|
+
|
|
82
122
|
## Не пересказывать то, у чего есть источник
|
|
83
123
|
|
|
84
124
|
- типы и поля контракта — `libs/common/proto/proto/<область>/v1/`, ссылкой;
|
|
@@ -26,6 +26,19 @@ description: Паттерн правила git-workflow. Брать на зав
|
|
|
26
26
|
|
|
27
27
|
Все четыре шага делает одна команда дерева, а не рука: делить их значит забывать третий.
|
|
28
28
|
|
|
29
|
+
**Очередь работ спрашивается до заведения задачи, а не после.** Найденное собственной сверкой
|
|
30
|
+
ощущается новым, и это ощущение — единственное, что стоит за решением завести задачу: команда
|
|
31
|
+
заведения отвечает за свои вызовы и о содержании очереди не знает ничего. Спрашивается она
|
|
32
|
+
поиском по словам темы, вместе с закрытым за последний месяц: дефект, закрытый и вернувшийся, —
|
|
33
|
+
та же работа, а не новая. Дубль стоит дорого — по нему проходит вся работа целиком, а сводить
|
|
34
|
+
две задачи в одну потом приходится руками.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
/opt/homebrew/bin/gh issue list --state all --limit 200 --search '<слова темы>' \
|
|
38
|
+
--json number,title,state
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
29
42
|
```bash
|
|
30
43
|
npm run task:new -- --title 'Письма владельцу не уходят молча' \
|
|
31
44
|
--label bug --label area:api --slug mail-owner-silence < описание.md
|
|
@@ -180,13 +193,13 @@ Docs-skip: правка только в тестах хука, зеркала у
|
|
|
180
193
|
каталог диагностики.
|
|
181
194
|
- `gh project` с `--owner` отвечает `unknown owner type`: владелец борды — другая учётная
|
|
182
195
|
запись, и правка идёт только через GraphQL.
|
|
183
|
-
-
|
|
196
|
+
- Заведённую задачу на борду сама она не забирает: репозиторий с ней не связан, и добавление
|
|
184
197
|
идёт отдельным вызовом. Два тикета так и остались вне очереди работ — поэтому все четыре
|
|
185
198
|
шага и делает `npm run task:new`, а не рука.
|
|
186
199
|
- Исполнитель у задачи не проставляется сам ни при заведении через веб, ни при добавлении на
|
|
187
200
|
борду: из девяноста девяти открытых задач он стоял у двух.
|
|
188
201
|
- Задача, заведённая через веб, мимо команды, на борду не попадает и гардом не отбивается —
|
|
189
|
-
он смотрит команду, а не
|
|
202
|
+
он смотрит команду, а не задачу. Ловится это только сверкой очереди.
|
|
190
203
|
- Колонка задачи сама не двигается ни от заведения ветки, ни от открытия PR: борда ветки не
|
|
191
204
|
видит вовсе, а связь с PR заполняет только поле «Linked pull requests». Взятие в работу не
|
|
192
205
|
ловит и сверка — ей ветка тоже не видна.
|
|
@@ -176,6 +176,20 @@ docker info --format 'демон: {{.ServerVersion}}'
|
|
|
176
176
|
содержимым или `403`, но не `401`. Каталог снимается в конце — раннер живёт между прогонами, и
|
|
177
177
|
пароль реестра остался бы лежать на диске владельца.
|
|
178
178
|
|
|
179
|
+
## Права токена спрашиваются до того, как конвейер на них обопрётся
|
|
180
|
+
|
|
181
|
+
Токен, которым ходят руками, и токен, которым ходит выкатка, — один и тот же ровно до первой
|
|
182
|
+
записи в реестр образов: области у него могут кончаться на чтении. Узнаётся это отказом, когда
|
|
183
|
+
весь путь выкатки уже написан, поэтому спрашивается раньше — и не догадкой, а заголовком ответа
|
|
184
|
+
хостинга:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
curl -sI -H "Authorization: Bearer <токен>" '<адрес хостинга>' | grep -i '^x-oauth-scopes:'
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Первая выкатка, сделанная руками из-за такого отказа, путь выкатки не проверяет — она проверяет
|
|
191
|
+
образы. Об этом говорится владельцу прямо: иначе зелёный прод читается как пройденный конвейер.
|
|
192
|
+
|
|
179
193
|
## Образ собирается под платформу прод-сервера
|
|
180
194
|
|
|
181
195
|
Машина владельца и прод-сервер бывают разной архитектуры. Без явной платформы собирается образ
|
|
@@ -40,6 +40,23 @@ git diff --name-only --diff-filter=U # что встало конфликт
|
|
|
40
40
|
| компаньон правила рядом со скилом | сохранением обеих сторон — те же две дописи в одну таблицу; после — `npm run check:specs` |
|
|
41
41
|
| список работ (`docs/BACKLOG.md`) | признаком отбора — паттерн `doc-style-sweep` |
|
|
42
42
|
|
|
43
|
+
## Коммит переносится черри-пиком
|
|
44
|
+
|
|
45
|
+
Ветка, которой коммит должен был уехать, ушла: влилась, была снята хостингом или заведена не под
|
|
46
|
+
ту задачу. Сам коммит при этом цел и лежит в отпавшей ветке.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
GIT_COMMITTER_NAME="<бот>" GIT_COMMITTER_EMAIL="<номер>+<бот>@users.noreply.github.com" \
|
|
50
|
+
git cherry-pick <sha>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Переменные подписи стоят на самой команде переноса. Черри-пик сохраняет автора коммита и ставит
|
|
54
|
+
коммиттером того, кто его зовёт, — то есть человека; коммиттера читает набор проверок перед
|
|
55
|
+
пушем, и чинится это уже перебазированием, а не правкой одного коммита.
|
|
56
|
+
|
|
57
|
+
Отпавшая ветка снимается с обеих сторон тем же ходом — иначе она стоит в перечне как незакрытая
|
|
58
|
+
работа.
|
|
59
|
+
|
|
43
60
|
## Что дописала ветка, видно только от точки расхождения
|
|
44
61
|
|
|
45
62
|
Конфликтный маркер показывает место, а не правку: сторона ветки в нём — её допись вместе со
|
|
@@ -107,5 +124,6 @@ PR описывал дерево на день, когда его написал
|
|
|
107
124
|
- Тело PR оставлено прежним: ревьювер читает утверждение о дереве, которого больше нет.
|
|
108
125
|
- Раздел, снятый главной веткой, вернулся «сохранением обеих сторон»: в спеке два экземпляра
|
|
109
126
|
одного абзаца, и снятый читается как действующий.
|
|
127
|
+
- Черри-пик взят без переменной коммиттера: автор у коммита прежний, коммиттер — человек, и отправку отбивает набор проверок.
|
|
110
128
|
- Мерж ушёл за подписью человека: переменных в команде слияния не было, а строка о подписи
|
|
111
129
|
лежит ниже команды и читается уже после коммита.
|
|
@@ -74,6 +74,11 @@ npx prisma migrate resolve --applied <новое имя>
|
|
|
74
74
|
|
|
75
75
|
## Частые промахи
|
|
76
76
|
|
|
77
|
+
- **Накат в образе настраивается файлом настройки, а не адресом в окружении.** Седьмая редакция
|
|
78
|
+
читает адрес хранилища только из своего файла настройки: ни объявление в схеме, ни переменная
|
|
79
|
+
окружения в составе прода его не заменяют. Этот файл кладётся в образ явно, рядом со схемой и
|
|
80
|
+
миграциями. Без него сборка зелёная целиком — генерация клиента на стадии сборки проходит, — а
|
|
81
|
+
отказывает первый же накат на узле.
|
|
77
82
|
- Метку времени ставит момент создания, а порядок применения лексикографический: миграция из
|
|
78
83
|
ветки, начатой раньше, встаёт перед той, от которой зависит. На существующей базе это
|
|
79
84
|
незаметно — падает только накат с нуля.
|
|
@@ -86,3 +91,9 @@ npx prisma migrate resolve --applied <новое имя>
|
|
|
86
91
|
через деплой, данные — через админку.
|
|
87
92
|
- Строки адресуются по первичному ключу, а не по маске: удаление по маске почты однажды унесло
|
|
88
93
|
вместе с тестовыми записями демонстрационные брони владельца.
|
|
94
|
+
- **Формой запроса вопрос гарда не снимается.** Условие по идентификатору он судит одинаково в
|
|
95
|
+
любой записи — что по одному, что по списку, — и на обе отвечает вопросом владельцу; отказ
|
|
96
|
+
приходит только на условие не по идентификатору. Там, где вопрос читается отказом, ход один:
|
|
97
|
+
назвать владельцу отбитую команду и попросить режим, в котором вопрос дойдёт, — а не
|
|
98
|
+
переписывать запрос, пока он не пройдёт. Иначе из захода уносят вывод о требованиях гарда,
|
|
99
|
+
которых у него нет.
|
|
@@ -185,6 +185,11 @@ PR выбираются отдельно, и `GH_TOKEN` для публикац
|
|
|
185
185
|
фразой владелец успевает влить PR, и всё сказанное о нём после этого — про вчерашний день. Так
|
|
186
186
|
владельцу и было предложено влить то, что он влил часом раньше.
|
|
187
187
|
|
|
188
|
+
Читается состояние и перед пушем в ветку, у которой есть заявка, а не только перед словом о
|
|
189
|
+
ней. Влитая заявка означает, что ветки на сервере уже нет: пуш её не обновит, а заведёт заново,
|
|
190
|
+
и вклад останется вне главной ветки. Ответ пуша говорит это одной строкой — отметкой о новой
|
|
191
|
+
ветке вместо перечня коммитов, — и её читают: на удачную отправку такой ответ похож целиком.
|
|
192
|
+
|
|
188
193
|
Открытый PR означает, что задача ждёт разбора, — колонка переставляется тем же движением:
|
|
189
194
|
|
|
190
195
|
```bash
|
|
@@ -276,5 +281,5 @@ in-review`, — и `npm run check:board` прогоняется ещё раз:
|
|
|
276
281
|
выглядя работающей. Так шестнадцать PR ждали разбора, которого никто не запрашивал.
|
|
277
282
|
- Метки поставлены по названию PR, а не прочитаны у задачи: область теряется, и по борде не
|
|
278
283
|
видно, что правка задела ещё и сайт.
|
|
279
|
-
- Задача закрыта не полностью, а метки перенесены целиком:
|
|
284
|
+
- Задача закрыта не полностью, а метки перенесены целиком: задача остаётся открытой, и это
|
|
280
285
|
говорится в теле PR, а не подразумевается строкой `Closes`.
|
|
@@ -17,6 +17,20 @@ description: Паттерн правила deploy-flow. Брать при раб
|
|
|
17
17
|
- Разбирается, что именно выкачено и чего приложению не хватает для работы, — включая ключ,
|
|
18
18
|
который живёт в окружении и экрана не имеет.
|
|
19
19
|
|
|
20
|
+
## Секрет выкатки — не ключ внешней службы
|
|
21
|
+
|
|
22
|
+
Ключи из этого паттерна живут в хранилище или в составе прода, и читает их приложение. Секреты
|
|
23
|
+
выкатки — ключ доступа к узлу, пароль реестра, адрес и токен приёма — приложением не читаются
|
|
24
|
+
вовсе: их читает конвейер, лежат они в настройках репозитория, и хранилище о них не знает.
|
|
25
|
+
|
|
26
|
+
Отсюда и разный ход при промахе. Ключ службы, которого не хватает, молчит на экране: возможность
|
|
27
|
+
не работает, а приложение отвечает. Секрет выкатки, которого не хватает, роняет шаг конвейера, и
|
|
28
|
+
до приложения дело не доходит вовсе — разбирают его в журнале задания, а не в браузере.
|
|
29
|
+
|
|
30
|
+
Про то, как секрет выкатки заводится и чем проверяется его право, говорит паттерн работы с
|
|
31
|
+
образами — `git-workflow-docker`, если дерево его разложило. Здесь остаётся граница: пришедший
|
|
32
|
+
за секретом выкатки читает дальше не этот текст.
|
|
33
|
+
|
|
20
34
|
## Ключ, заводимый владельцем, живёт в хранилище, а не в окружении
|
|
21
35
|
|
|
22
36
|
Такой ключ лежит строкой в хранилище, зашифрованной ключом шифрования секретов; рядом открытая
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: git-workflow-stack
|
|
3
3
|
kind: pattern
|
|
4
4
|
rule: git-workflow
|
|
5
|
-
description: Паттерн правила git-workflow. Брать, когда из одного основания заведено больше двух
|
|
5
|
+
description: Паттерн правила git-workflow. Брать, когда работы идут одна за другой либо когда из одного основания уже заведено больше двух веток: ветвление чередой от предыдущей, основание заявки, порядок вливания снизу вверх, перевливание главной по факту конфликта. Один конфликт — паттерн git-workflow-merge.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Стопка заявок из одного основания
|
|
@@ -17,6 +17,53 @@ description: Паттерн правила git-workflow. Брать, когда
|
|
|
17
17
|
- За заход сделано несколько работ, и они лежат в дереве невыложенными.
|
|
18
18
|
- Решается, в каком порядке отдавать накопленное владельцу.
|
|
19
19
|
|
|
20
|
+
## Череда: ветвиться от предыдущей, а не от главной
|
|
21
|
+
|
|
22
|
+
Стопка из одного основания — то, чего надо избежать. Работы, идущие подряд, ветвятся подряд:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# первая работа череды — от главной, как обычно
|
|
26
|
+
git checkout -b <КЛЮЧ>-<номер>-<slug> origin/main
|
|
27
|
+
|
|
28
|
+
# каждая следующая — от предыдущей ветки, а не от origin/main
|
|
29
|
+
git checkout -b <КЛЮЧ>-<следующий>-<slug> <КЛЮЧ>-<номер>-<slug>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Правка предыдущей лежит тогда в общем предке, и сводить два разных изменения одного файла не
|
|
33
|
+
приходится вовсе. Расхождение всплывает при ветвлении — у того, у кого обе правки свои и под
|
|
34
|
+
рукой, — а не при слиянии, у владельца, у которого нет ни одной.
|
|
35
|
+
|
|
36
|
+
От главной ветвится первая работа череды и всякая, которая предыдущей не касается: череда — это
|
|
37
|
+
про соседние работы, а не про все подряд.
|
|
38
|
+
|
|
39
|
+
## Заявка череды стоит на предыдущей ветке
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gh pr create --base <предыдущая ветка> --title '[<КЛЮЧ>-<номер>] <что сделано>' --body-file <файл>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Основанием главная не ставится: разбор тогда показывает свою правку вперемешку со всем, что под
|
|
46
|
+
ней. Влитую нижнюю хостинг переносит сам — базой её заявки-наследницы становится главная.
|
|
47
|
+
|
|
48
|
+
Порядок вливания стоит в теле каждой заявки строкой «стоит на #<номер>, вливать после него»:
|
|
49
|
+
владелец вливает по списку, а родство веток по списку не видно.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# порядок череды целиком — снизу вверх
|
|
53
|
+
gh pr list --state open --json number,headRefName,baseRefName \
|
|
54
|
+
--jq '.[] | "\(.number)\t\(.headRefName)\tна \(.baseRefName)"'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Чего в череде не делают
|
|
58
|
+
|
|
59
|
+
- **Историю нижней ветки не переписывают.** Ни `rebase`, ни силовая отправка: вершина верхней
|
|
60
|
+
становится достижимой из её основания, и хостинг закрывает заявку верхней как слитую — при том
|
|
61
|
+
что в главной её правок нет. Отставшая нижняя чинится вливанием главной в неё и дальше вверх.
|
|
62
|
+
- **Череду не вливают из середины.** Влитая не по порядку тащит за собой всё, что под ней, — и
|
|
63
|
+
разбор той работы уже не состоится.
|
|
64
|
+
- **Готовые ветки не копят.** Череда не отменяет того, что единица работы — влитая заявка: она
|
|
65
|
+
лишь делает безопасной ту длину, которая всё же накопилась.
|
|
66
|
+
|
|
20
67
|
## Единица работы — влитая заявка, а не открытая
|
|
21
68
|
|
|
22
69
|
Открытый черновик работой не является: кнопка слияния у него заблокирована, в главной ветке его
|
|
@@ -65,6 +112,21 @@ docs/archive/README.md merge=union
|
|
|
65
112
|
Сложение ставится только на указатели, где правка всегда добавляющая. На текст, который
|
|
66
113
|
переписывают, оно оставит в файле обе редакции.
|
|
67
114
|
|
|
115
|
+
**Сложение сторон метку сливаемости не снимает, и вливать главную по ней нельзя.** Хостинг
|
|
116
|
+
считает сливаемость своим приёмом и настроек слияния не читает: ветка, тронувшая сложенный
|
|
117
|
+
указатель, помечается конфликтующей всё равно. Спрошенная у него стопка отвечает «конфликтует»
|
|
118
|
+
целиком, и вливание по этому ответу — то же вливание во все ветки, что и без сложения: раздел
|
|
119
|
+
ниже велит вливать главную по факту конфликта, а факт этот хостинг называет про каждую ветку
|
|
120
|
+
стопки. Пятнадцать заявок разом простояли так за один заход. Проверяется одной командой: то же
|
|
121
|
+
слияние без драйвера даёт конфликтный маркер, с драйвером идёт чисто — значит метку держит
|
|
122
|
+
указатель, а не правка.
|
|
123
|
+
|
|
124
|
+
**Указатель, куда дописывает каждая ветка стопки, из стопки убирается, а не складывается.**
|
|
125
|
+
Сложение — починка проявления: конфликта нет, метка есть, вливать по-прежнему приходится.
|
|
126
|
+
Спрашивается это до заведения веток: отвечает ли указатель на вопрос, которого не закрывает
|
|
127
|
+
обход каталога. Не отвечает — он снимается, и площадь пересечения стопки падает до настоящих
|
|
128
|
+
общих файлов.
|
|
129
|
+
|
|
68
130
|
## Порядок вливания задаётся заранее и называется владельцу
|
|
69
131
|
|
|
70
132
|
Порядок считается до открытия заявок — по тому, кто какие файлы правит:
|
|
@@ -33,6 +33,11 @@ docs/specs/<домен>/
|
|
|
33
33
|
та же связь сценариев с тестами. Домен, у которого половина поддоменов описана, а половина
|
|
34
34
|
заведена пустыми каталогами, зелёным не бывает.
|
|
35
35
|
|
|
36
|
+
Работа, задевшая домен и его поддомен, пишет две договорённости, а не одну. Префикс сценариев у
|
|
37
|
+
поддомена свой, а второго префикса одному спеку сверка не даёт: сценарии такой работы
|
|
38
|
+
разъезжаются по двум нумерациям — по одной на каждый спек, в который вольются. Замысел называет
|
|
39
|
+
обе, и вливаются они порознь, каждая в свой спек.
|
|
40
|
+
|
|
36
41
|
## Обязательные разделы
|
|
37
42
|
|
|
38
43
|
`## Зачем` · `## Терминология` с подразделом `### Как это называется в интерфейсе` ·
|
|
@@ -95,11 +100,17 @@ docs/specs/<домен>/
|
|
|
95
100
|
`Не покрыто: <причина>`, сценарий с неполным тестом — `Покрытие: частичное — <чего не
|
|
96
101
|
хватает>`.
|
|
97
102
|
|
|
103
|
+
Сценарий, который проверить нечем в принципе, не заводится вовсе. Пометка о непокрытом говорит
|
|
104
|
+
«теста ещё нет» и обещает, что он появится; там, где проверки не существует, обещания нет, а
|
|
105
|
+
помеченный сценарий висит в наборе вечно, читается как долг и заставляет каждого следующего
|
|
106
|
+
заново выяснять, не пора ли его закрыть. Правило, ради которого сценарий хотели завести,
|
|
107
|
+
остаётся правилом: его держат строка в компаньоне и запись в истории изменений, и этого довольно.
|
|
108
|
+
|
|
98
109
|
Номер в идентификаторе живёт так:
|
|
99
110
|
|
|
100
111
|
| Что случилось | Что делается с номером |
|
|
101
112
|
| ----------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
102
|
-
| сценарий добавили | берётся следующий свободный — наибольший выданный
|
|
113
|
+
| сценарий добавили | берётся следующий свободный — наибольший выданный **во всех ветках** плюс один, а не дырка в середине |
|
|
103
114
|
| обещание изменили | номер тот же, заголовок теста правится тем же коммитом |
|
|
104
115
|
| сценарий удалили | номер остаётся пустым и новому сценарию не отдаётся; тест удаляется вместе со сценарием |
|
|
105
116
|
| номера захотелось сжать | не пересчитываются: связь с тестами держит только номер, а прогон остаётся зелёным при обеих правках |
|
|
@@ -107,6 +118,15 @@ docs/specs/<домен>/
|
|
|
107
118
|
Номер записывается так же, как у соседей в этом же файле: сверка ищет его шаблоном, и номер,
|
|
108
119
|
записанный иначе, не совпадёт ни в спеке, ни в заголовке теста.
|
|
109
120
|
|
|
121
|
+
**Свободный номер ищется во всех ветках, а не в одной главной.** Соседняя работа держит свои
|
|
122
|
+
номера на диске и в главную ещё не въехала: шесть номеров так раздали дважды, и двигаться
|
|
123
|
+
пришлось той работе, чья договорённость не влита. Номер — единственное, чем сценарий связан с
|
|
124
|
+
тестом, и отданный второй раз он оставляет старую ссылку правильной на вид и ведущей не туда.
|
|
125
|
+
|
|
126
|
+
Спрашивается это командой дерева, если дерево её завело: она читает заголовки сценариев во всех
|
|
127
|
+
ветках — своих и удалённых — и печатает первый свободный за наибольшим занятым. Имя команды
|
|
128
|
+
называет компаньон правила.
|
|
129
|
+
|
|
110
130
|
## Порядок работы
|
|
111
131
|
|
|
112
132
|
1. Задача заводится сценариями: что станет верно, когда работа закончится.
|
|
@@ -115,6 +135,10 @@ docs/specs/<домен>/
|
|
|
115
135
|
4. `npm run check:specs` — до пуша.
|
|
116
136
|
5. Приёмка идёт по сценариям, а не по пересказу правки.
|
|
117
137
|
|
|
138
|
+
Правило, обещающее человеку видимый результат, подтверждается на работающем приложении, а не
|
|
139
|
+
выводом из графа вызовов. Чтением подтверждаются заголовки, связь с привязками и форма данных;
|
|
140
|
+
правило, которое подтвердить не на чем, уезжает открытым вопросом и утверждением не пишется.
|
|
141
|
+
|
|
118
142
|
## Частые промахи
|
|
119
143
|
|
|
120
144
|
- Выросший домен делят на новые домены, а не на поддомены: новый домен приходится заводить в
|
|
@@ -139,10 +163,19 @@ docs/specs/<домен>/
|
|
|
139
163
|
- Закон, названный в тексте, но забытый в строке `**Законы:**`: по закону тогда не узнать,
|
|
140
164
|
какие домены на нём стоят.
|
|
141
165
|
- Правка `.proto` без спеков задетых доменов: `docs-guard` отбивает такой коммит.
|
|
166
|
+
- **Правило, выведенное из графа вызовов, ошибается беззвучно.** Читается оно так же уверенно,
|
|
167
|
+
как замеренное, и сверка привязки его пропускает — символ на месте, просто описывает он не то.
|
|
168
|
+
Два правила одного спека оказались перевёрнутыми: связь шла не между хранилищами, а через
|
|
169
|
+
слушающий их компонент, — и оба чуть не стали задачей на дефект, которого нет.
|
|
170
|
+
|
|
142
171
|
- **Выросший домен делится на поддомены, а не на новые домены.** Новый домен пришлось бы
|
|
143
172
|
заводить в указателе, сверять с кодом отдельно и объяснять, чем он соседу не поддомен;
|
|
144
173
|
поддомен остаётся в своём домене и наследует его контракт. Соседний домен заводится только
|
|
145
174
|
тогда, когда предмет живёт своей сущностью.
|
|
175
|
+
- **Наибольший выданный номер ищется по всему домену командой, а не глазами по хвосту файла.**
|
|
176
|
+
Номера в файле сценариев идут не по порядку: правки вставляли их к соседям по смыслу, и
|
|
177
|
+
последняя строка максимума не показывает. Шесть новых номеров из одиннадцати легли на занятые
|
|
178
|
+
— поймала это сверка спеков, а не чтение, и переписывать пришлось заодно заголовки тестов.
|
|
146
179
|
- **Границу между доменами проводит владелец, а не автор очередной правки.** Автор видит свою
|
|
147
180
|
правку, а не то, чем предмет обрастёт: домен, заведённый по ходу дела, через месяц оказывается
|
|
148
181
|
половиной соседнего, и разводить их приходится вместе с номерами сценариев.
|
|
@@ -74,6 +74,17 @@ description: Правило под «Закон о поставке». Брат
|
|
|
74
74
|
---
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
Под шапкой стоит строка требования к соседним ресурсам — тем, без которых статьи правила не
|
|
78
|
+
исполняются:
|
|
79
|
+
|
|
80
|
+
```markdown
|
|
81
|
+
**Требует:** `hooks/<гард>.sh`, `checks/<проверка>.mjs`
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Ресурсы называются именами пакета, а не путями дерева. Строки нет — правило не требует ничего;
|
|
85
|
+
пустой она не бывает. Выводить требование из фразы в тексте нельзя: разложено у потребителя не
|
|
86
|
+
всё, и текст, сказавший «правку отбивает гард», врёт в дереве, где гарда нет.
|
|
87
|
+
|
|
77
88
|
Разделы: `## Как это называется здесь` · `## Где это лежит` · `## Как закон применяется
|
|
78
89
|
здесь` · `## Чего из закона здесь нет` · `## Паттерны` · `## Ловушки`.
|
|
79
90
|
|
|
@@ -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
|
+
есть строка, а куда эта строка ведёт — не говорит ничего.
|