@rt-tools/agent-kit 0.5.3 → 0.7.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/README.md +15 -1
- package/assets/checks/check-file-size.mjs +127 -0
- package/assets/checks/check-push-gate.mjs +139 -0
- package/assets/checks/rt-kit-checks.config.mjs +21 -0
- package/assets/defaults/gate-map.sh +90 -34
- package/assets/defaults/project.sh +26 -3
- package/assets/hooks/skill-gate-layers.sh +156 -0
- package/assets/hooks/skill-gate.sh +11 -2
- package/assets/laws/code-structure.md +3 -0
- package/assets/laws/delivery.md +9 -0
- package/assets/laws/observability.md +46 -0
- package/assets/laws/project-documentation.md +4 -0
- package/assets/laws/reuse-first.md +2 -0
- package/assets/laws/verifiability.md +5 -0
- package/assets/patterns/browser-verification-stand.md +22 -2
- package/assets/patterns/doc-style-trace.md +111 -0
- package/assets/patterns/git-workflow-commit.azure.md +18 -0
- package/assets/patterns/git-workflow-commit.github.md +19 -1
- package/assets/patterns/git-workflow-commit.gitlab.md +18 -0
- package/assets/patterns/git-workflow-docker.md +203 -0
- package/assets/patterns/git-workflow-secrets.md +93 -0
- package/assets/patterns/observability-record.md +114 -0
- package/assets/patterns/seo-verify.md +1 -1
- package/assets/patterns/spec-driven-domain.md +2 -2
- package/assets/patterns/spec-driven-rule.md +5 -0
- package/assets/patterns/styling-bem-sheet.md +178 -0
- package/assets/patterns/task-flow-close.md +20 -0
- package/assets/patterns/task-flow-resume.md +5 -0
- package/assets/patterns/translations-content.md +107 -0
- package/assets/patterns/translations-key.md +1 -1
- package/assets/rules/angular-patterns.md +5 -0
- package/assets/rules/browser-verification.md +17 -12
- package/assets/rules/component-structure.md +6 -2
- package/assets/rules/doc-style.md +16 -0
- package/assets/rules/git-workflow.azure.md +60 -1
- package/assets/rules/git-workflow.github.md +67 -1
- package/assets/rules/git-workflow.gitlab.md +61 -1
- package/assets/rules/lists.md +13 -0
- package/assets/rules/observability.md +147 -0
- package/assets/rules/permissions.md +23 -0
- package/assets/rules/reuse-first.md +9 -0
- package/assets/rules/seo.md +57 -9
- package/assets/rules/shared-code.md +6 -0
- package/assets/rules/spec-driven.md +9 -0
- package/assets/rules/styling-bem.md +34 -1
- package/assets/rules/task-flow.md +5 -0
- package/assets/rules/testing.md +46 -8
- package/assets/rules/translations.md +11 -5
- package/assets/rules/typescript-conventions.md +5 -0
- package/lib/assets.d.ts +1 -1
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +2 -4
- package/lib/assets.js.map +1 -1
- package/lib/catalog.d.ts +73 -0
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +121 -0
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +84 -5
- package/lib/commands.js.map +1 -1
- package/lib/integrity.d.ts +25 -12
- package/lib/integrity.d.ts.map +1 -1
- package/lib/integrity.js +40 -18
- package/lib/integrity.js.map +1 -1
- package/lib/proposals.d.ts +9 -1
- package/lib/proposals.d.ts.map +1 -1
- package/lib/proposals.js +11 -2
- package/lib/proposals.js.map +1 -1
- package/lib/retired.d.ts +30 -0
- package/lib/retired.d.ts.map +1 -0
- package/lib/retired.js +19 -0
- package/lib/retired.js.map +1 -0
- package/lib/sync.d.ts +45 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +44 -10
- package/lib/sync.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.7.0.tgz +0 -0
- package/assets/laws/application/money.md +0 -41
- package/assets/laws/application/ownership.md +0 -32
- package/assets/patterns/ownership-scope-resolve.md +0 -69
- package/assets/patterns/pricing-quote.md +0 -71
- package/assets/rules/ownership-scope.md +0 -63
- package/assets/rules/pricing.md +0 -64
- package/rt-tools-agent-kit-0.5.3.tgz +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Слои гейта правил: требования, которые приходят ПОВЕРХ доменного.
|
|
3
|
+
#
|
|
4
|
+
# Доменное правило выбирается один раз по пути файла — у правки один предмет, и правило под него
|
|
5
|
+
# одно. Слоёв поверх него полтора десятка: доступ к среде исполнения виден только в тексте
|
|
6
|
+
# правки, наблюдаемость приходит вместе с доменом, а не вместо него, проза и ведение работы
|
|
7
|
+
# судят тот же файл вторым признаком. Вместе они не помещаются в карту гейта, которую читают
|
|
8
|
+
# целиком, — поэтому лежат здесь.
|
|
9
|
+
#
|
|
10
|
+
# Подключается из `skill-gate.sh` в его же оболочке: читает `$input`, `$target` и `$req` и
|
|
11
|
+
# дописывает имена правил в `$req`. Отдельным процессом слои возвращали бы то же самое через
|
|
12
|
+
# диск.
|
|
13
|
+
#
|
|
14
|
+
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нечем разобрать вход — слой молчит. Разбор входа здесь побочная
|
|
15
|
+
# работа, и её поломка не имеет права остановить правку.
|
|
16
|
+
#
|
|
17
|
+
# Адреса дерева слои не знают: где у него бэкенд, витрина и сквозные тесты, говорит само дерево
|
|
18
|
+
# — функцией `skill_layer_skip <правило> <цель>` в своей карте гейта. Нет её — слой действует
|
|
19
|
+
# везде, где подошёл его признак.
|
|
20
|
+
|
|
21
|
+
# Уже названное вторым разом не требуется: отказ, перечисляющий одно правило дважды, читается
|
|
22
|
+
# как два разных требования.
|
|
23
|
+
rt_layer_add() {
|
|
24
|
+
case " $req " in
|
|
25
|
+
*" $1 "*) return 0 ;;
|
|
26
|
+
esac
|
|
27
|
+
req="${req:+$req }$1"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Дерево вправе снять слой с места, где признак законен: прямое обращение к среде исполнения на
|
|
31
|
+
# бэкенде, чтение окружения в обвязке, заведение файла в сквозных тестах.
|
|
32
|
+
rt_layer_allowed() {
|
|
33
|
+
command -v skill_layer_skip >/dev/null 2>&1 || return 0
|
|
34
|
+
skill_layer_skip "$1" "$2" && return 1
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Текст правки читается один раз на все слои: разбор входа стоит дороже самих признаков.
|
|
39
|
+
rt_layer_payload=""
|
|
40
|
+
if command -v jq >/dev/null 2>&1; then
|
|
41
|
+
rt_layer_payload="$(printf '%s' "$input" \
|
|
42
|
+
| jq -r '[.tool_input.content, .tool_input.text, .tool_input.new_string, (.tool_input.edits[]?.new_string)]
|
|
43
|
+
| map(select(. != null)) | join("\n")' 2>/dev/null)"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Спека проверяет поведение, а не заводит его: там нужен `testing`, и слои поведения её обходят.
|
|
47
|
+
rt_layer_is_spec=1
|
|
48
|
+
case "$target" in *.spec.ts) rt_layer_is_spec=0 ;; esac
|
|
49
|
+
|
|
50
|
+
# --- слой по тексту: обращение к среде исполнения ---------------------------------------------
|
|
51
|
+
#
|
|
52
|
+
# Путь говорит, ЧТО за файл, а обращение к глобальному объекту видно только в содержимом: гейт,
|
|
53
|
+
# знающий один путь, пропускает его молча. Значение, полученное внедрением, признаком не
|
|
54
|
+
# считается — это уже зависимость, а не прямое обращение.
|
|
55
|
+
if [ -n "$rt_layer_payload" ] && [ "$rt_layer_is_spec" = 1 ]; then
|
|
56
|
+
case "$target" in
|
|
57
|
+
*/main.ts|*/main.server.ts|*/server.ts|*/index.html) ;;
|
|
58
|
+
*.ts|*.html)
|
|
59
|
+
if printf '%s' "$rt_layer_payload" | grep -qE \
|
|
60
|
+
'globalThis|PLATFORM_ID|isPlatformBrowser|defaultView|(^|[^[:alnum:]_.#$])window[[:space:]]*\.'; then
|
|
61
|
+
rt_layer_allowed platform-access "$target" && rt_layer_add platform-access
|
|
62
|
+
fi
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# --- слой по тексту: наблюдаемость ------------------------------------------------------------
|
|
68
|
+
#
|
|
69
|
+
# Чтение переменной окружения и есть тот момент, когда заводится новая необязательная
|
|
70
|
+
# возможность. Сводка старта перечисляет их руками, и забывшая дописать себя не попадёт ни в
|
|
71
|
+
# один из трёх списков — на проде она выглядит не выключенной, а несуществующей.
|
|
72
|
+
if [ -n "$rt_layer_payload" ] && [ "$rt_layer_is_spec" = 1 ]; then
|
|
73
|
+
case "$target" in
|
|
74
|
+
*.ts)
|
|
75
|
+
if printf '%s' "$rt_layer_payload" | grep -qE 'process\.env'; then
|
|
76
|
+
rt_layer_allowed observability "$target" && rt_layer_add observability
|
|
77
|
+
fi
|
|
78
|
+
;;
|
|
79
|
+
esac
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# --- слой по тексту: общий код ----------------------------------------------------------------
|
|
83
|
+
#
|
|
84
|
+
# Заводимое число-настройка и заводимое перечисление — тот момент, когда рядом с уже общим
|
|
85
|
+
# появляется копия. Каждая копия сама по себе исправна, и ни линт, ни сборка второй не видят.
|
|
86
|
+
# Спеки не в счёт: там значения местные, это фикстуры.
|
|
87
|
+
if [ -n "$rt_layer_payload" ] && [ "$rt_layer_is_spec" = 1 ]; then
|
|
88
|
+
case "$target" in
|
|
89
|
+
*.ts)
|
|
90
|
+
if printf '%s' "$rt_layer_payload" | grep -qE \
|
|
91
|
+
'(^|[[:space:]])(export[[:space:]]+)?const[[:space:]]+[A-Z][A-Z0-9_]*[[:space:]]*(:[[:space:]]*number[[:space:]]*)?=[[:space:]]*[0-9]|(^|[[:space:]])export[[:space:]]+enum[[:space:]]'; then
|
|
92
|
+
rt_layer_allowed shared-code "$target" && rt_layer_add shared-code
|
|
93
|
+
fi
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# --- слой по пути: классы Angular -------------------------------------------------------------
|
|
99
|
+
#
|
|
100
|
+
# Компонент и стор — тоже классы: сигнальный API входов, обнаружение изменений и место подписки
|
|
101
|
+
# живут в `angular-patterns`, а первым слоем эти файлы уходят в устройство компонента и в
|
|
102
|
+
# соглашения языка, где ничего этого нет.
|
|
103
|
+
if [ "$rt_layer_is_spec" = 1 ]; then
|
|
104
|
+
case "$target" in
|
|
105
|
+
*.component.ts|*.store.ts)
|
|
106
|
+
rt_layer_allowed angular-patterns "$target" && rt_layer_add angular-patterns
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# --- слой по пути: проза ----------------------------------------------------------------------
|
|
112
|
+
#
|
|
113
|
+
# Формат спека держит `spec-driven`, а как формулировать — `doc-style`, и нужен он не только
|
|
114
|
+
# спекам. Список известного у проверки — та же проза: его поле объясняет, что перечисленное
|
|
115
|
+
# отказом не считается, а сверка текстов читает только `.md`.
|
|
116
|
+
#
|
|
117
|
+
# Хозяйство самого агента слой обходит: правило на него — оно само, и карта гейта решает про
|
|
118
|
+
# эти файлы целиком. Слой, наложенный поверх, требовал бы правило там, где карта его нарочно
|
|
119
|
+
# не назвала.
|
|
120
|
+
case "$target" in
|
|
121
|
+
*/.claude/*) ;;
|
|
122
|
+
*.md|*-allowlist.json) rt_layer_allowed doc-style "$target" && rt_layer_add doc-style ;;
|
|
123
|
+
esac
|
|
124
|
+
|
|
125
|
+
# --- слой по пути: ведение работы -------------------------------------------------------------
|
|
126
|
+
#
|
|
127
|
+
# Папка задачи, договорённость о продукте до кода и линия работ — первые файлы, которые
|
|
128
|
+
# заводятся в работе. Требование ловит на них того, кто пошёл мимо порядка: «пришла новая
|
|
129
|
+
# задача» инструментом не является, и поймать это больше нечем.
|
|
130
|
+
case "$target" in
|
|
131
|
+
*/docs/tasks/*|*/docs/specs/*/proposed/*|*/docs/plans/*)
|
|
132
|
+
rt_layer_allowed task-flow "$target" && rt_layer_add task-flow
|
|
133
|
+
;;
|
|
134
|
+
esac
|
|
135
|
+
|
|
136
|
+
# --- слой по заведению файла ------------------------------------------------------------------
|
|
137
|
+
#
|
|
138
|
+
# Ничего не пишется с нуля, и спрашивается это там, где решение и принимается, — на заведении
|
|
139
|
+
# нового файла: у правки существующего опора уже выбрана, а требовать правило на каждую строку
|
|
140
|
+
# значит сделать его фоном.
|
|
141
|
+
case "$target" in
|
|
142
|
+
*/docs/*) ;;
|
|
143
|
+
*.spec.ts|*.stories.ts) ;;
|
|
144
|
+
*.ts|*.html|*.scss)
|
|
145
|
+
[ -f "$target" ] || { rt_layer_allowed reuse-first "$target" && rt_layer_add reuse-first; }
|
|
146
|
+
;;
|
|
147
|
+
esac
|
|
148
|
+
|
|
149
|
+
# Куда встаёт заведённая проверка и какой формы у неё список известного — утверждения `testing`,
|
|
150
|
+
# и нужны они ровно в момент заведения: у существующей проверки и место в гейте, и форма списка
|
|
151
|
+
# уже выбраны.
|
|
152
|
+
case "$target" in
|
|
153
|
+
*/check-*.mjs|*-allowlist.json)
|
|
154
|
+
[ -f "$target" ] || { rt_layer_allowed testing "$target" && rt_layer_add testing; }
|
|
155
|
+
;;
|
|
156
|
+
esac
|
|
@@ -62,6 +62,11 @@ case "$tool" in
|
|
|
62
62
|
# приходит в обычный сервис, а число-настройка в обычный класс.
|
|
63
63
|
written="$(printf '%s' "$input" | jq -r '[.tool_input.content, .tool_input.text, .tool_input.new_string, (.tool_input.edits[]?.new_string)] | map(select(. != null)) | join("\n")' 2>/dev/null)"
|
|
64
64
|
req="$(skill_for edit "$target" "$written" 2>/dev/null)"
|
|
65
|
+
# Слои поверх доменного правила лежат отдельным файлом и зовутся в этой же оболочке:
|
|
66
|
+
# доменное правило выбирается один раз по пути, а слоёв полтора десятка, и вместе они не
|
|
67
|
+
# помещаются в карту, которую читают целиком. Нет файла — гейт остаётся одним слоем.
|
|
68
|
+
# shellcheck disable=SC1090
|
|
69
|
+
[ -f "$rt_hooks_dir/skill-gate-layers.sh" ] && . "$rt_hooks_dir/skill-gate-layers.sh" 2>/dev/null
|
|
65
70
|
# Род правки для наблюдения. Одно расширение, без пути и без имени файла: наблюдение
|
|
66
71
|
# уезжает наружу, и всё, кроме рода, там было бы адресом этого дерева.
|
|
67
72
|
case "${target##*/}" in
|
|
@@ -123,7 +128,11 @@ req="$want"
|
|
|
123
128
|
[ -f "$rt_hooks_dir/observe.sh" ] && . "$rt_hooks_dir/observe.sh" 2>/dev/null
|
|
124
129
|
command -v rt_note >/dev/null 2>&1 && rt_note gate-deny "res=$req" "kind=$kind" "sid=$sid"
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
# Запасной ход называется прямо в отказе: правило, заведённое в этой же ветке, реестру правил
|
|
132
|
+
# неизвестно — он собирается на запуске сессии, а гейт читает диск. Без этой строки следующий
|
|
133
|
+
# заход ищет обход перебором и обычно находит не тот.
|
|
134
|
+
fallback="Если инструмент такого имени не знает, правило завели после начала сессии — прочитай ${rules_dir}/${req}/SKILL.md и спутник рядом с ним."
|
|
135
|
+
reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill и повтори действие. ${fallback} Для этой области это происходит один раз за сессию."
|
|
127
136
|
|
|
128
137
|
# Правило называет свой закон одним словом, а слоёв законов два: общий лежит в корне, закон
|
|
129
138
|
# приложения — в каталоге под ним. Путь ищется, а не собирается из имени, иначе отказ ведёт в
|
|
@@ -134,7 +143,7 @@ if [ -n "$law" ]; then
|
|
|
134
143
|
law_path="$laws_dir/${law}.md"
|
|
135
144
|
[ -f "$root/$law_path" ] || law_path="$laws_dir/application/${law}.md"
|
|
136
145
|
[ -f "$root/$law_path" ] \
|
|
137
|
-
&& reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill — оно применяет закон ${law_path} к этому дереву — и повтори действие. Для этой области это происходит один раз за сессию."
|
|
146
|
+
&& reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill — оно применяет закон ${law_path} к этому дереву — и повтори действие. ${fallback} Для этой области это происходит один раз за сессию."
|
|
138
147
|
fi
|
|
139
148
|
|
|
140
149
|
jq -n --arg r "$reason" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}' 2>/dev/null \
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
причина названа рядом.
|
|
21
21
|
- **Отметка об устаревании — повод убрать, а не повод оставить.** Устаревшее объявление,
|
|
22
22
|
которое молча продолжает работать, переживает того, кто его пометил.
|
|
23
|
+
- **Файл читается целиком.** Длина, при которой его читают по частям, объявлена одним числом на
|
|
24
|
+
все роды файлов, и накопленное до объявления перечислено поимённо: перечень отмечает долг, а
|
|
25
|
+
не выдаёт разрешение.
|
|
23
26
|
|
|
24
27
|
## Открытые вопросы
|
|
25
28
|
|
package/assets/laws/delivery.md
CHANGED
|
@@ -75,3 +75,12 @@
|
|
|
75
75
|
его написали, а разбора ждёт днями: за это время главная ветка вливается в ветку, и
|
|
76
76
|
утверждение отчёта о соседних файлах становится неправдой молча — тел отчётов не читает ни
|
|
77
77
|
одна проверка. Всё, что вливается в ветку после публикации отчёта, — повод перечитать его.
|
|
78
|
+
- **Слияние в главную ветку ещё не означает, что правка доехала.** Отказ выкатки не трогает ни
|
|
79
|
+
задачу, ни очередь работ, поэтому расхождение главной ветки с тем, что работает, обязано быть
|
|
80
|
+
видно там, где очередь читают. Иначе следующие работы вливаются поверх поломки, которую не
|
|
81
|
+
приносили, и каждая выглядит доехавшей.
|
|
82
|
+
- **Состоявшаяся поломка разбирается записью, которая переживает задачу.** Починка уезжает
|
|
83
|
+
веткой, задача закрывается — и причина, по которой приложение встало, остаётся знанием одного
|
|
84
|
+
исполнителя. Запись называет, что сломалось, чем это стало видно и почему починка чинит
|
|
85
|
+
причину, а не признак; живёт она среди описаний состоявшегося, а не там, что умирает вместе с
|
|
86
|
+
задачей.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Закон о наблюдаемости
|
|
2
|
+
|
|
3
|
+
Что владелец знает о работе своего приложения. Если о поломке можно узнать только через доступ
|
|
4
|
+
к серверу, владелец узнаёт о ней от гостя и с опозданием.
|
|
5
|
+
|
|
6
|
+
**Ревизия:** 2026-08-13
|
|
7
|
+
|
|
8
|
+
## Статьи
|
|
9
|
+
|
|
10
|
+
- **Отказ приложения виден владельцу без доступа к серверу.** На сервер владелец не заходит,
|
|
11
|
+
поэтому всё, что видно только оттуда, для него недоступно.
|
|
12
|
+
- **Отказ хранится и после перезапуска приложения, и спустя месяцы.** Поломку разбирают уже
|
|
13
|
+
после того, как она случилась, а вывод приложения к этому времени затирается.
|
|
14
|
+
- **Все отказы одного обращения находятся по одному признаку.** При десятке обращений в секунду
|
|
15
|
+
по времени их не разделить.
|
|
16
|
+
- **Тот, кто наткнулся на отказ, получает номер обращения и может его назвать.** Иначе по жалобе
|
|
17
|
+
нечего искать.
|
|
18
|
+
- **Наружу уходит номер обращения и общий текст ошибки. Подробности остаются внутри.**
|
|
19
|
+
Подробности показывают, как приложение устроено.
|
|
20
|
+
- **Подробности отказа закрыты правом.** В них видно, кто был в системе и чем именно приложение
|
|
21
|
+
сломалось.
|
|
22
|
+
- **Владелец узнаёт о новом отказе сам, без захода на экран.** Иначе поломку заметят только
|
|
23
|
+
тогда, когда до экрана дойдут руки.
|
|
24
|
+
- **У обращения к чужой службе есть предел ожидания.** Молчащая служба отличается от отказавшей
|
|
25
|
+
только временем: без предела обращение висит до умолчания среды, отказ не наступает вовсе, и
|
|
26
|
+
записывать нечего. Всё это время владелец видит исправную работу.
|
|
27
|
+
- **Обращение к чужой службе оставляет запись, и заводится она до обращения.** Запись после
|
|
28
|
+
ответа говорит только о том, что дошло: попытка, оборвавшаяся посередине, не отличается от не
|
|
29
|
+
начатой, а владелец видит лишь удачные исходы.
|
|
30
|
+
- **Отказ не записывается в ущерб работе приложения.** Ответ не ждёт записи, запрос из-за неё не
|
|
31
|
+
падает. Если записать не удалось, это видно.
|
|
32
|
+
- **Приложение не пишет отказы о собственной записи отказов.** Иначе поломка хранилища порождает
|
|
33
|
+
поток, который сам себя разгоняет.
|
|
34
|
+
- **Отказом считается то, что не сработало, а не каждый обслуженный запрос.** Иначе поток чужих
|
|
35
|
+
обращений определяет, сколько приложение о себе хранит.
|
|
36
|
+
- **У хранилища отказов есть предел, и он проверяется до того, как кончится место.** Иначе
|
|
37
|
+
хранилище отказов положит приложение, за которым следит.
|
|
38
|
+
- **Секреты и личные данные вычищаются перед записью.** После записи их убирают правкой данных,
|
|
39
|
+
а это дороже и не всегда возможно.
|
|
40
|
+
|
|
41
|
+
## Открытые вопросы
|
|
42
|
+
|
|
43
|
+
- **Q-O-1.** Куда девать отказ, случившийся до того, как приложение поднялось. Хранилища в этот
|
|
44
|
+
момент ещё нет. Сейчас такой отказ остаётся только в выводе приложения.
|
|
45
|
+
- **Q-O-2.** Хранить ли отказы обвязки — того, что стоит перед приложением и отдаёт страницы.
|
|
46
|
+
Её вывод к приложению не приходит, и читать его надо отдельно.
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
— это намерение, а не свойство приложения: сверить его не с чем, и оно проходит любую
|
|
34
34
|
проверку. Машине это не поручить: открытый вопрос пишется теми же словами, что и обещание,
|
|
35
35
|
и проверка отбивала бы оба.
|
|
36
|
+
- **Полнота текстов проверяется и со стороны работы, а не только со стороны текста.** Обход
|
|
37
|
+
написанного судит каждое утверждение, но утверждения, которого нет, в этом обходе нет тоже:
|
|
38
|
+
приём, применённый и нигде не описанный, так не находится никогда. Поэтому закрытая работа
|
|
39
|
+
спрашивается отдельно — оставила она след в текстах или явно его не требует.
|
|
36
40
|
- **Документ утверждает о состоявшемся, а не о том, что должно сработать.** Лечение,
|
|
37
41
|
записанное готовым до того, как его прогнали, дороже отсутствия записи: следующий читатель
|
|
38
42
|
берёт его за проверенное — и берёт в тот день, когда лечение понадобилось, а времени на
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## Статьи
|
|
10
10
|
|
|
11
|
+
- **У каждого приложения один источник вида, и он у них разный.** Взять контрол из чужого
|
|
12
|
+
источника значит принести на экран форму, которой в этом приложении нет больше нигде.
|
|
11
13
|
- **Готовое берут, а не пишут заново.** Своя копия расходится с оригиналом с первой же правки,
|
|
12
14
|
и одинаковые с виду места начинают вести себя по-разному.
|
|
13
15
|
- **Отойти от общего вида может решить только владелец.** Сделать своё вместо готового
|
|
@@ -56,3 +56,8 @@
|
|
|
56
56
|
род события и версия одинаковы везде, где стоит слой правил; путь, домен и имя дерева
|
|
57
57
|
принадлежат одному дереву и в чужом месте не значат ничего, кроме утечки. Держится это
|
|
58
58
|
проверкой на выносящей стороне, а не памятью того, кто пишет.
|
|
59
|
+
- **Проверка, которая сама сломалась, работу не останавливает.** Отказ инструмента не является
|
|
60
|
+
найденным нарушением, и остановленная им работа стоит до того, как его починят.
|
|
61
|
+
- **Решение, зависящее от текущего момента, получает момент снаружи.** Иначе проверить его можно
|
|
62
|
+
только подкруткой часов, а подкрученные часы действуют и на всё, что оказалось рядом: проверка
|
|
63
|
+
начинает зависеть от того, что к ней отношения не имеет.
|
|
@@ -50,12 +50,12 @@ npx nx build admin --base-href=/
|
|
|
50
50
|
Angular DevTools, нужна ещё и dev-конфигурация (`--configuration=development`): прод-сборка не
|
|
51
51
|
публикует `window.ng`. Выводы о размере бандла и минификации на такой сборке делать нельзя.
|
|
52
52
|
|
|
53
|
-
Сессия кладётся в `localStorage['
|
|
53
|
+
Сессия кладётся в `localStorage['<ключ сессии админки>']` **строкой JSON** (`JSON.stringify(token)`),
|
|
54
54
|
иначе приложение её не прочитает. Токен не подписывается руками, а берётся у живого API:
|
|
55
55
|
`POST /<область>.v1.AuthService/Login`. Команду с паролем классификатор блокирует — обходить не
|
|
56
56
|
надо, спрашивать разрешение у владельца.
|
|
57
57
|
|
|
58
|
-
Взять уже открытую сессию нельзя: чтение
|
|
58
|
+
Взять уже открытую сессию нельзя: чтение того же ключа из браузера
|
|
59
59
|
блокируется. Оба пути к своему стенду упираются в пароль, поэтому остаётся третий — смотреть
|
|
60
60
|
на админке владельца, где вход уже сделан. Свой стенд нужен, только когда проверяют
|
|
61
61
|
прод-сборку, `--base-href` или конфиг nginx; чтобы просто посмотреть экраны, он не нужен.
|
|
@@ -131,8 +131,28 @@ pnpm install --frozen-lockfile # из ../<префикс>-base: node_mod
|
|
|
131
131
|
- Оба стенда держат поднятыми одновременно: если сравнивать по памяти между двумя запусками,
|
|
132
132
|
заметишь только то, что успел запомнить.
|
|
133
133
|
|
|
134
|
+
## Состояние портов снимается до первой сборки захода
|
|
135
|
+
|
|
136
|
+
Серверы владельца ложатся и без твоего участия: сайт отдавал 404 на все свои адреса ещё до
|
|
137
|
+
первой сборки захода, а API замолчало посреди него. Без замера «до» падение нельзя ни
|
|
138
|
+
приписать своей сборке, ни снять с неё подозрение.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
for u in http://localhost:{{apiPort}}/health http://localhost:{{sitePort}}/ http://localhost:{{adminPort}}/; do
|
|
142
|
+
printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$u")" "$u"
|
|
143
|
+
done
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Замер — это ответ, а не `lsof`: порт бывает занят собранным артефактом прошлой сессии, и он
|
|
147
|
+
отвечает 200 старым кодом.
|
|
148
|
+
|
|
134
149
|
## Частые промахи
|
|
135
150
|
|
|
151
|
+
- **Одиночная сборка проекта серверы переживают, и отказываться от неё незачем.** Замерено
|
|
152
|
+
ответом до и после: все порты остались за своими процессами. Осторожность здесь стоит дороже
|
|
153
|
+
проверки — целая команда паттерна `seo-verify` осталась незапущенной ровно потому, что сборку
|
|
154
|
+
сочли опасной, не замерив. Сборка из кэша замером не является: она не собирает вовсе, и видно
|
|
155
|
+
это по её длительности.
|
|
136
156
|
- Свой дев-сервер не поднимать: сайт на {{sitePort}}, админка на {{adminPort}}, API на {{apiPort}} уже подняты
|
|
137
157
|
владельцем, и второй экземпляр отбивается гардом.
|
|
138
158
|
- **Общая сборка глушит все три дев-сервера владельца, а не только API.** После
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doc-style-trace
|
|
3
|
+
kind: pattern
|
|
4
|
+
rule: doc-style
|
|
5
|
+
description: Паттерн правила doc-style. Брать, когда полнота текстов проверяется со стороны работы, а не со стороны текста — обратный проход по закрытым задачам: признак отбора машиной, чего он не видит, три исхода по каждой задаче, граница «код не правится». Не брать для разбора документа, накопившего список работ, — это паттерн doc-style-sweep.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Обратный проход: закрытые задачи против текстов
|
|
9
|
+
|
|
10
|
+
Паттерн правила `doc-style`. Что при этом должно быть верно — закон
|
|
11
|
+
`docs/constitution/project-documentation.md`.
|
|
12
|
+
|
|
13
|
+
## Когда брать
|
|
14
|
+
|
|
15
|
+
- Проверяется не то, верен ли текст, а то, есть ли он вообще.
|
|
16
|
+
- Разбирается работа, закрытая до того, как в закрытие задачи вошёл шаг приведения текстов.
|
|
17
|
+
- Волна разбора со стороны текста кончилась, а находок в ней вышло мало.
|
|
18
|
+
|
|
19
|
+
## Проход со стороны текста не находит того, чего не написали
|
|
20
|
+
|
|
21
|
+
Он читает написанное и судит каждое утверждение; утверждения, которого нет, в обходе нет
|
|
22
|
+
тоже. Со стороны работы находок на порядок больше: в первой части семь находок из восьми
|
|
23
|
+
легли туда, где текста не было вовсе, а не туда, где он устарел.
|
|
24
|
+
|
|
25
|
+
## Признак отбора — ветка внесла код и не тронула ни одного текста
|
|
26
|
+
|
|
27
|
+
Отбирается машиной и чтения не требует. Что ветка внесла на самом деле, отвечает история, а
|
|
28
|
+
не папка задачи: папка разбирается при закрытии, и таблица следа задачи до главной ветки не
|
|
29
|
+
доезжает вовсе.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git log --merges --format='%H %s' <главная ветка> | grep -E 'from [^/]+/<ключ задач>-[0-9]+-'
|
|
33
|
+
git diff --name-only <мерж>^1 <мерж>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Признак считается вычитанием, а не двумя списками путей: код — всё, что не `.md`, текст —
|
|
37
|
+
любой `.md` вне описания прошлого и папок задач. Списки, написанные руками, разошлись по обоим
|
|
38
|
+
краям сразу, и разошлись молча.
|
|
39
|
+
|
|
40
|
+
Список текстов пропустил самые читаемые тексты дерева: тот, что приходит в контекст каждой
|
|
41
|
+
сессии целиком, и тот, что описывает устройство дерева. Три задачи, тронувшие ровно их, попали
|
|
42
|
+
в выборку как бесследные — и во вторую часть прохода попали второй раз, уже как тронувшие
|
|
43
|
+
текст.
|
|
44
|
+
|
|
45
|
+
Список кода пропустил обвязку: гарды, конвейер и файлы выкатки в нём не значились, и две
|
|
46
|
+
задачи, правившие только их, не попали ни в одну выборку вовсе. Нашлись они не признаком, а
|
|
47
|
+
сверкой двух выборок между собой — её и стоит прогнать перед каждой следующей частью:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
comm -23 <список бесследных> <разобранные первой частью> # кого не прочитал никто
|
|
51
|
+
comm -12 <разобранные первой частью> <список тронувших текст> # кого прочитали дважды
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Часть назначает самая узкая область задачи, и метки бывает нет вовсе
|
|
55
|
+
|
|
56
|
+
Выборка, которую признак отобрал, одним заходом не читается, и делится она по области —
|
|
57
|
+
метке области у задачи. Меток у задачи бывает несколько; часть назначает самая узкая из них, а
|
|
58
|
+
порядок сужения выбирается один раз на весь проход и записывается в замысел вместе с таблицей
|
|
59
|
+
частей. При обратном порядке самые широкие области забрали бы себе все спорные задачи, и у
|
|
60
|
+
узких не осталось бы почти ничего.
|
|
61
|
+
|
|
62
|
+
Задача без единой метки области не попадает ни в одну часть вовсе — ни по какому порядку
|
|
63
|
+
сужения. Признак её отобрал, читать её некому, и видно это только пересчётом:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
awk -F'\t' 'NR==FNR{k[$1]=1;next} k[$1] && $2==""{print}' <номера выборки> <задачи с метками>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Такую задачу относят к части по предмету руками, и это решение записывается в разбор: иначе
|
|
70
|
+
следующая часть пересчитает выборку и найдёт её снова непрочитанной.
|
|
71
|
+
|
|
72
|
+
## Исходов у задачи три, а не два
|
|
73
|
+
|
|
74
|
+
| Исход | Признак |
|
|
75
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| следа не требует | приём нигде не повторён: вёрстка своего экрана, разовая правка по просьбе владельца |
|
|
77
|
+
| след есть | утверждение о работе стоит в правиле, паттерне или спеке — в том числе внесённое отдельной задачей следом |
|
|
78
|
+
| следа нет | приём применён и нигде не описан — это и есть находка |
|
|
79
|
+
|
|
80
|
+
Приём, записанный отдельной задачей следом, промахом не является: работа сделана одной
|
|
81
|
+
задачей, запись приёма заведена другой, и в очереди работ видны обе. Отличается это чтением
|
|
82
|
+
соседних по времени задач той же области, а не признаком.
|
|
83
|
+
|
|
84
|
+
Худшего случая признак не видит вовсе: ветка тронула соседний текст и обошла тот, который
|
|
85
|
+
описывает её собственную работу. Такие задачи остаются следующей части прохода.
|
|
86
|
+
|
|
87
|
+
## Граница «код не правится» и её единственное исключение
|
|
88
|
+
|
|
89
|
+
Нашлось место, где неправ код, — заводится задача, проход идёт дальше. Кодом при этом не
|
|
90
|
+
считается то, что описывает сверяемое правило: комментарий в шапке проверки и заголовок
|
|
91
|
+
теста. Заголовок несёт идентификатор сценария, и без него новый сценарий значится непокрытым
|
|
92
|
+
при живом тесте.
|
|
93
|
+
|
|
94
|
+
## Находка кладётся в тот слой, которому принадлежит
|
|
95
|
+
|
|
96
|
+
- приём повторён и решается в коде — утверждение правила с привязкой в именах дерева;
|
|
97
|
+
- готовый код и порядок действий — паттерн;
|
|
98
|
+
- обещание, которое видит человек, — сценарий спека домена с прежней нумерацией;
|
|
99
|
+
- расхождение с договорённостью — текст статьи владельцу, файл закона не правится.
|
|
100
|
+
|
|
101
|
+
## Частые промахи
|
|
102
|
+
|
|
103
|
+
- Состав части взят из прошлого захода, а не пересчитан признаком. Выборки живут в
|
|
104
|
+
скретчпаде сессии и умирают вместе с ней; в дерево они не кладутся — деление на части
|
|
105
|
+
свойство прохода, а не продукта. Пересчёт стоит двух команд выше и даёт тот же список, а
|
|
106
|
+
состав, принятый на слово, нечем сверить с соседними частями — именно сверкой находятся те,
|
|
107
|
+
кого не прочитал никто.
|
|
108
|
+
- Задача судится по своей папке: её разобрали при закрытии, и следа там не осталось.
|
|
109
|
+
- «След есть» по одному упоминанию: упоминание в соседнем правиле приёма не описывает.
|
|
110
|
+
- Находка записана только в паттерн: правило читают перед каждой правкой, паттерн — по имени.
|
|
111
|
+
- Признак пересчитан на новом списке путей без сверки на выборке руками.
|
|
@@ -201,6 +201,11 @@ az repos pr show --id 205 \
|
|
|
201
201
|
|
|
202
202
|
Владельцу называют то, что прочитали, а не то, что заказывали.
|
|
203
203
|
|
|
204
|
+
Перечитывают его и по времени, а не только после вызовов, которые молча ничего не сделали:
|
|
205
|
+
состояние PR читается перед тем, как что-либо о нём сказать. Между «прогон зелёный» и следующей
|
|
206
|
+
фразой владелец успевает влить PR, и всё сказанное о нём после этого — про вчерашний день. Так
|
|
207
|
+
владельцу и было предложено влить то, что он влил часом раньше.
|
|
208
|
+
|
|
204
209
|
Открытый PR означает, что элемент ждёт разбора, — состояние переставляется тем же движением:
|
|
205
210
|
|
|
206
211
|
```bash
|
|
@@ -236,6 +241,14 @@ npm run task:move -- 86 in-review
|
|
|
236
241
|
сделано>`, тем же номером, что стоит у элемента и в имени ветки.
|
|
237
242
|
12. **Очередь работ сходится** — `npm run check:board`.
|
|
238
243
|
13. **Состояние PR прочитано, а не выведено из кодов возврата.**
|
|
244
|
+
14. **Набор взят из файла конвейера, а не собран по памяти.** Гейт пуша заведомо уже: он стоит
|
|
245
|
+
между командой и пушем, и всё, что дольше секунд, из него вынесено. Что гоняет конвейер,
|
|
246
|
+
написано в его файле — этот список и повторяется локально; зелёный гейт полнотой набора не
|
|
247
|
+
является.
|
|
248
|
+
15. **Набор пересмотрен после вливания главной ветки.** Он выбирается по тому, что ветка везёт
|
|
249
|
+
теперь, а не по тому, что правил автор. Ветка, не тронувшая ни строки показа, прогоняет
|
|
250
|
+
снимки витрин: с момента вливания их гоняет конвейер на её коде, и красное придёт на её
|
|
251
|
+
отчёт.
|
|
239
252
|
|
|
240
253
|
Сразу после публикации элемент переводится в разбор, и сверка очереди прогоняется ещё раз: до
|
|
241
254
|
открытия PR состояние она не судит, а после открытия расхождение видит.
|
|
@@ -243,6 +256,11 @@ npm run task:move -- 86 in-review
|
|
|
243
256
|
Сделанное рассуждением и сделанное замером в теле PR разводятся прямо: непроверенное,
|
|
244
257
|
названное проверенным, ревьювер принимает за проверенное.
|
|
245
258
|
|
|
259
|
+
**Раздел «Чем подтверждено» называет и то, что не гонялось.** Список одного прогнанного
|
|
260
|
+
неотличим от полного набора, и ревьювер по нему решает, что можно не перепроверять. Цена ошибки
|
|
261
|
+
здесь не красный конвейер, а доверие к разделу: однажды прочитанный как полнота, дальше он
|
|
262
|
+
перепроверяется весь.
|
|
263
|
+
|
|
246
264
|
## Частые промахи
|
|
247
265
|
|
|
248
266
|
- Область и итерация не заданы: элемент заведён, но на доску команды не попал.
|
|
@@ -168,7 +168,7 @@ PR [<КЛЮЧ>-86] Письмо владельцу с незаполнен
|
|
|
168
168
|
задача [<КЛЮЧ>-101] Вернуть оверлей загрузки таблицы и включить stylelint гейтом
|
|
169
169
|
PR [<КЛЮЧ>-101] Stylelint включён гейтом
|
|
170
170
|
|
|
171
|
-
задача [<КЛЮЧ>-212] Сайт не собирается: компонентам кита проставлен префикс
|
|
171
|
+
задача [<КЛЮЧ>-212] Сайт не собирается: компонентам кита проставлен префикс приложения вместо своего
|
|
172
172
|
PR [<КЛЮЧ>-212] Виджет переписки зовёт кит его собственными именами
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -249,6 +249,11 @@ $GH api "repos/$REPO/pulls/321" \
|
|
|
249
249
|
Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
|
|
250
250
|
PR выбираются отдельно, и `GH_TOKEN` для публикации — всегда токен бота.
|
|
251
251
|
|
|
252
|
+
Перечитывают его и по времени, а не только после вызовов, которые молча ничего не сделали:
|
|
253
|
+
состояние PR читается перед тем, как что-либо о нём сказать. Между «прогон зелёный» и следующей
|
|
254
|
+
фразой владелец успевает влить PR, и всё сказанное о нём после этого — про вчерашний день. Так
|
|
255
|
+
владельцу и было предложено влить то, что он влил часом раньше.
|
|
256
|
+
|
|
252
257
|
Открытый PR означает, что задача ждёт разбора, — колонка переставляется тем же движением:
|
|
253
258
|
|
|
254
259
|
```bash
|
|
@@ -293,6 +298,14 @@ npm run task:move -- 86 in-review
|
|
|
293
298
|
номером в заголовке; PR один на задачу, и закрывает он её целиком.
|
|
294
299
|
13. **Состояние PR прочитано, а не выведено из кодов возврата** — автор `<бот>`,
|
|
295
300
|
ревьювер — владелец, метки те же, что у задачи. Владельцу называют прочитанное.
|
|
301
|
+
14. **Набор взят из файла конвейера, а не собран по памяти.** Гейт пуша заведомо уже: он стоит
|
|
302
|
+
между командой и пушем, и всё, что дольше секунд, из него вынесено. Что гоняет конвейер,
|
|
303
|
+
написано в его файле — этот список и повторяется локально; зелёный гейт полнотой набора не
|
|
304
|
+
является.
|
|
305
|
+
15. **Набор пересмотрен после вливания главной ветки.** Он выбирается по тому, что ветка везёт
|
|
306
|
+
теперь, а не по тому, что правил автор. Ветка, не тронувшая ни строки показа, прогоняет
|
|
307
|
+
снимки витрин: с момента вливания их гоняет конвейер на её коде, и красное придёт на её
|
|
308
|
+
отчёт.
|
|
296
309
|
|
|
297
310
|
Сразу после публикации задача переставляется в разбор — `npm run task:move -- <номер>
|
|
298
311
|
in-review`, — и `npm run check:board` прогоняется ещё раз: до открытия PR колонку он не судит,
|
|
@@ -301,6 +314,11 @@ in-review`, — и `npm run check:board` прогоняется ещё раз:
|
|
|
301
314
|
Сделанное рассуждением и сделанное замером в теле PR разводятся прямо: непроверенное,
|
|
302
315
|
названное проверенным, ревьювер принимает за проверенное.
|
|
303
316
|
|
|
317
|
+
**Раздел «Чем подтверждено» называет и то, что не гонялось.** Список одного прогнанного
|
|
318
|
+
неотличим от полного набора, и ревьювер по нему решает, что можно не перепроверять. Цена ошибки
|
|
319
|
+
здесь не красный конвейер, а доверие к разделу: однажды прочитанный как полнота, дальше он
|
|
320
|
+
перепроверяется весь.
|
|
321
|
+
|
|
304
322
|
## Частые промахи
|
|
305
323
|
|
|
306
324
|
- `gh` в оболочке пользователя подменён — звать `/opt/homebrew/bin/gh` напрямую.
|
|
@@ -221,6 +221,11 @@ glab mr view 205 --output json \
|
|
|
221
221
|
Учётная запись, из-под которой пришлось пушить, в этот вызов не переносится: пуш и авторство
|
|
222
222
|
MR выбираются отдельно, и токен для публикации — всегда токен машинной работы.
|
|
223
223
|
|
|
224
|
+
Перечитывают его и по времени, а не только после вызовов, которые молча ничего не сделали:
|
|
225
|
+
состояние MR читается перед тем, как что-либо о нём сказать. Между «прогон зелёный» и следующей
|
|
226
|
+
фразой владелец успевает влить MR, и всё сказанное о нём после этого — про вчерашний день. Так
|
|
227
|
+
владельцу и было предложено влить то, что он влил часом раньше.
|
|
228
|
+
|
|
224
229
|
Открытый MR означает, что задача ждёт разбора, — список переставляется тем же движением:
|
|
225
230
|
|
|
226
231
|
```bash
|
|
@@ -256,6 +261,14 @@ npm run task:move -- 86 in-review
|
|
|
256
261
|
сделано>`, тем же номером, что стоит у задачи и в имени ветки.
|
|
257
262
|
12. **Очередь работ сходится** — `npm run check:board`.
|
|
258
263
|
13. **Состояние MR прочитано, а не выведено из кодов возврата.**
|
|
264
|
+
14. **Набор взят из файла конвейера, а не собран по памяти.** Гейт пуша заведомо уже: он стоит
|
|
265
|
+
между командой и пушем, и всё, что дольше секунд, из него вынесено. Что гоняет конвейер,
|
|
266
|
+
написано в его файле — этот список и повторяется локально; зелёный гейт полнотой набора не
|
|
267
|
+
является.
|
|
268
|
+
15. **Набор пересмотрен после вливания главной ветки.** Он выбирается по тому, что ветка везёт
|
|
269
|
+
теперь, а не по тому, что правил автор. Ветка, не тронувшая ни строки показа, прогоняет
|
|
270
|
+
снимки витрин: с момента вливания их гоняет конвейер на её коде, и красное придёт на её
|
|
271
|
+
отчёт.
|
|
259
272
|
|
|
260
273
|
Сразу после публикации задача переставляется в разбор, и сверка очереди прогоняется ещё раз: до
|
|
261
274
|
открытия MR список она не судит, а после открытия расхождение видит.
|
|
@@ -263,6 +276,11 @@ npm run task:move -- 86 in-review
|
|
|
263
276
|
Сделанное рассуждением и сделанное замером в теле MR разводятся прямо: непроверенное,
|
|
264
277
|
названное проверенным, ревьювер принимает за проверенное.
|
|
265
278
|
|
|
279
|
+
**Раздел «Чем подтверждено» называет и то, что не гонялось.** Список одного прогнанного
|
|
280
|
+
неотличим от полного набора, и ревьювер по нему решает, что можно не перепроверять. Цена ошибки
|
|
281
|
+
здесь не красный конвейер, а доверие к разделу: однажды прочитанный как полнота, дальше он
|
|
282
|
+
перепроверяется весь.
|
|
283
|
+
|
|
266
284
|
## Частые промахи
|
|
267
285
|
|
|
268
286
|
- Метка списка не поставлена при заведении: задача есть, а на доске её нет. Доска показывает
|