@rt-tools/agent-kit 0.8.2 → 0.9.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 +13 -0
- package/assets/agents/rules-reviewer.md +83 -0
- package/assets/checks/board.github.mjs +48 -1
- package/assets/checks/check-board.github.mjs +84 -1
- package/assets/checks/check-dupes.mjs +66 -6
- package/assets/checks/check-lib-layers.mjs +13 -524
- package/assets/checks/check-specs.mjs +61 -747
- package/assets/checks/check-styles.mjs +185 -15
- package/assets/checks/lib-boundaries.mjs +143 -0
- package/assets/checks/lib-common.mjs +149 -0
- package/assets/checks/lib-domains.mjs +205 -0
- package/assets/checks/lib-manifests.mjs +60 -0
- package/assets/checks/lib-reexports.mjs +101 -0
- package/assets/checks/rt-kit-checks.config.mjs +26 -0
- package/assets/checks/spec-anchors.mjs +297 -0
- package/assets/checks/spec-common.mjs +222 -0
- package/assets/checks/spec-contract.mjs +152 -0
- package/assets/checks/spec-scenarios.mjs +201 -0
- package/assets/commands/feedback.md +95 -0
- package/assets/commands/rules-review.md +98 -0
- package/assets/commands/skill-curator.md +39 -22
- package/assets/defaults/project.sh +8 -0
- package/assets/docs/GLOSSARY.md +21 -20
- package/assets/hooks/git-guard-push-tests.sh +8 -4
- package/assets/hooks/reuse-first-guard.sh +16 -2
- package/assets/hooks/skill-gate.sh +1 -1
- package/assets/hooks/sql-guard-parse.sh +187 -0
- package/assets/hooks/sql-guard-request.sh +117 -0
- package/assets/hooks/sql-guard-target.sh +134 -0
- package/assets/hooks/sql-guard-write.sh +212 -0
- package/assets/hooks/sql-guard.sh +26 -596
- package/assets/hooks/task-flow-guard.sh +16 -2
- package/assets/hooks/waiting-turn-guard.sh +116 -0
- package/assets/laws/delivery.md +35 -0
- package/assets/laws/project-documentation.md +18 -0
- package/assets/laws/work-conduct.md +25 -0
- package/assets/patterns/admin-lists-screen.md +25 -14
- package/assets/patterns/admin-nav-item.md +1 -1
- package/assets/patterns/component-structure-new.md +1 -1
- package/assets/patterns/entity-aside.md +4 -2
- package/assets/patterns/git-workflow-commit.azure.md +74 -2
- package/assets/patterns/git-workflow-commit.github.md +75 -2
- package/assets/patterns/git-workflow-commit.gitlab.md +75 -4
- package/assets/patterns/git-workflow-docker.md +30 -0
- package/assets/patterns/observability-record.md +9 -0
- package/assets/patterns/shared-code-new.md +2 -2
- package/assets/patterns/task-flow-close.md +160 -47
- package/assets/patterns/task-flow-handoff.md +1 -1
- package/assets/patterns/task-flow-resume.md +3 -3
- package/assets/patterns/task-flow-start.md +32 -5
- package/assets/rules/angular-patterns.md +22 -0
- package/assets/rules/api-layer.md +25 -0
- package/assets/rules/browser-verification.md +32 -0
- package/assets/rules/component-structure.md +21 -0
- package/assets/rules/dependencies.md +22 -0
- package/assets/rules/doc-style.md +24 -0
- package/assets/rules/entity-conventions.needs-admin.md +21 -0
- package/assets/rules/entity-models.md +21 -0
- package/assets/rules/git-workflow.azure.md +57 -1
- package/assets/rules/git-workflow.github.md +89 -2
- package/assets/rules/git-workflow.gitlab.md +56 -1
- package/assets/rules/lib-layers.md +29 -0
- package/assets/rules/lists.md +37 -10
- package/assets/rules/navigation.md +21 -0
- package/assets/rules/observability.needs-app.md +23 -0
- package/assets/rules/permissions.md +23 -0
- package/assets/rules/platform-access.md +21 -0
- package/assets/rules/reuse-first.md +20 -0
- package/assets/rules/seo.md +19 -0
- package/assets/rules/shared-code.md +20 -1
- package/assets/rules/spec-driven.md +32 -0
- package/assets/rules/styling-bem.md +19 -0
- package/assets/rules/task-flow.md +148 -18
- package/assets/rules/testing.md +62 -0
- package/assets/rules/translations.md +21 -0
- package/assets/rules/typescript-conventions.md +28 -0
- package/assets/samples/specs/_template/spec.md +83 -0
- package/assets/samples/tasks/_template/grill.md +28 -0
- package/assets/samples/tasks/_template/plan.md +39 -0
- package/assets/samples/tasks/_template/progress.md +23 -0
- package/assets/skills/agent-kit.md +52 -2
- package/assets/templates/proposal.md +21 -0
- package/assets/templates/rule.md +31 -2
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +115 -87
- package/bin/agent-kit.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/lib/argv.d.ts.map +1 -1
- package/lib/argv.js +6 -4
- package/lib/argv.js.map +1 -1
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +2 -1
- package/lib/assets.js.map +1 -1
- package/lib/cargo.d.ts +20 -0
- package/lib/cargo.d.ts.map +1 -1
- package/lib/cargo.js.map +1 -1
- package/lib/cascade.d.ts +55 -0
- package/lib/cascade.d.ts.map +1 -0
- package/lib/cascade.js +131 -0
- package/lib/cascade.js.map +1 -0
- package/lib/catalog.d.ts +0 -75
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +44 -127
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +153 -85
- package/lib/commands.js.map +1 -1
- package/lib/companion.d.ts.map +1 -1
- package/lib/companion.js +5 -5
- package/lib/companion.js.map +1 -1
- package/lib/config.d.ts +12 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +11 -5
- package/lib/config.js.map +1 -1
- package/lib/enroll.d.ts +56 -0
- package/lib/enroll.d.ts.map +1 -0
- package/lib/enroll.js +123 -0
- package/lib/enroll.js.map +1 -0
- package/lib/freshness.d.ts.map +1 -1
- package/lib/freshness.js +31 -17
- package/lib/freshness.js.map +1 -1
- package/lib/hooks-map.d.ts +30 -0
- package/lib/hooks-map.d.ts.map +1 -1
- package/lib/hooks-map.js +80 -18
- package/lib/hooks-map.js.map +1 -1
- package/lib/integrity.d.ts +1 -2
- package/lib/integrity.d.ts.map +1 -1
- package/lib/integrity.js +0 -1
- package/lib/integrity.js.map +1 -1
- package/lib/observations.d.ts.map +1 -1
- package/lib/observations.js +25 -12
- package/lib/observations.js.map +1 -1
- package/lib/order.d.ts +10 -0
- package/lib/order.d.ts.map +1 -0
- package/lib/order.js +14 -0
- package/lib/order.js.map +1 -0
- package/lib/picker.d.ts.map +1 -1
- package/lib/picker.js +8 -2
- package/lib/picker.js.map +1 -1
- package/lib/plan.js +1 -1
- package/lib/plan.js.map +1 -1
- package/lib/proposals.d.ts.map +1 -1
- package/lib/proposals.js +25 -8
- package/lib/proposals.js.map +1 -1
- package/lib/sections.js +1 -1
- package/lib/sections.js.map +1 -1
- package/lib/ship.d.ts.map +1 -1
- package/lib/ship.js +9 -1
- package/lib/ship.js.map +1 -1
- package/lib/shipment.d.ts.map +1 -1
- package/lib/shipment.js +14 -10
- package/lib/shipment.js.map +1 -1
- package/lib/snapshot.d.ts.map +1 -1
- package/lib/snapshot.js +2 -1
- package/lib/snapshot.js.map +1 -1
- package/lib/stamp.js +1 -1
- package/lib/stamp.js.map +1 -1
- package/lib/sync.d.ts +12 -2
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +11 -10
- package/lib/sync.js.map +1 -1
- package/lib/vars.d.ts.map +1 -1
- package/lib/vars.js +2 -3
- package/lib/vars.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.9.0.tgz +0 -0
- package/rt-tools-agent-kit-0.8.2.tgz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# rt-hook: PreToolUse Edit|Write|MultiEdit
|
|
2
|
+
# rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
|
|
3
3
|
# Требует: hooks/profile-check.sh
|
|
4
4
|
# PreToolUse guard for Edit|Write|MultiEdit: код не пишется раньше замысла.
|
|
5
5
|
#
|
|
@@ -49,9 +49,23 @@ case "$tool" in
|
|
|
49
49
|
# Второй ярус: та же правка, положенная командой оболочки. Без него отказ гарда обходится
|
|
50
50
|
# сменой не инструмента, а способа записи — перенаправлением, `sed -i`, интерпретатором с
|
|
51
51
|
# heredoc. Разбор — `2026-08-15-guard-denied-shell-wrote-anyway.md`.
|
|
52
|
-
|
|
52
|
+
#
|
|
53
|
+
# Терминал среды исполняет ту же командную строку и кладёт её в то же поле: без этих двух
|
|
54
|
+
# имён гард стоял бы объявленным на них и молча пропускал — состояние хуже необъявленного,
|
|
55
|
+
# потому что снаружи выглядит закрытым.
|
|
56
|
+
Bash | mcp__webstorm__execute_terminal_command | mcp__webstorm__execute_tool)
|
|
53
57
|
cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)"
|
|
54
58
|
[ -z "$cmd" ] && exit 0
|
|
59
|
+
# Универсальный исполнитель прячет настоящую команду во вложенной строке: без её разбора
|
|
60
|
+
# путь стоит за кавычкой, и до него не дотягивается ни один образец.
|
|
61
|
+
if [ "$tool" = "mcp__webstorm__execute_tool" ] && command -v perl >/dev/null 2>&1; then
|
|
62
|
+
inner="$(printf '%s' "$cmd" | perl -0ne '
|
|
63
|
+
if (/--command(?:=|\s+)(?:"((?:[^"\\]|\\.)*)"|\x27([^\x27]*)\x27|(.+))/s) {
|
|
64
|
+
print defined $1 ? $1 : (defined $2 ? $2 : $3);
|
|
65
|
+
}
|
|
66
|
+
' 2>/dev/null)"
|
|
67
|
+
[ -n "$inner" ] && cmd="$inner"
|
|
68
|
+
fi
|
|
55
69
|
rt_needs rt_shell_writes task-flow-guard || exit 0
|
|
56
70
|
rt_needs rt_shell_paths task-flow-guard || exit 0
|
|
57
71
|
rt_shell_writes "$cmd" || exit 0
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: Stop
|
|
3
|
+
# Гард ожидания: ход, сообщающий владельцу о чужом шаге, не заканчивается, пока в нём не было ни
|
|
4
|
+
# одного действия по следующей задаче. Stop.
|
|
5
|
+
#
|
|
6
|
+
# Зачем именно так. Статья «ожидание прогона работой не занимают» держится памятью исполнителя, и
|
|
7
|
+
# держится плохо: образец сообщения владельцу кончается фразой о следующей задаче, а фраза
|
|
8
|
+
# исполняется как обещание — заход произносит её и кончает ход. Ход, в котором не сделано ничего,
|
|
9
|
+
# ничем себя не выдаёт: ни правкой файла, ни командой, — и промах виден только владельцу, только
|
|
10
|
+
# по тому, что работа не двигается, и только когда он спросит прямо.
|
|
11
|
+
#
|
|
12
|
+
# Чужой шаг узнаётся по двум признакам, и оба берутся из хода, а не из сети. Первый — открытие
|
|
13
|
+
# PR: работа отдана, и дальше её двигает владелец. Второй — прочитанный красный прогон: чинить
|
|
14
|
+
# его надо, но ход, в котором его прочитали и не сделали ничего, — та же пустота. Само чтение
|
|
15
|
+
# прогона признаком не является: конец прогона читают и затем, чтобы пойти чинить; значит
|
|
16
|
+
# красный ответ, а он лежит в выводе команды — там же, в записи хода.
|
|
17
|
+
#
|
|
18
|
+
# Спросить хостинг было бы точнее, но сетевой вызов на завершении хода падает вместе со связью и
|
|
19
|
+
# отбивал бы работу вместо промаха.
|
|
20
|
+
#
|
|
21
|
+
# Что считается действием: заведение задачи, заведение ветки, перевод колонки очереди работ,
|
|
22
|
+
# заведение папки задачи. Набор открыт и пополняется правкой — полнота его открытый вопрос, а не
|
|
23
|
+
# обещание.
|
|
24
|
+
#
|
|
25
|
+
# Чего гард не судит. Ход, в котором о чужом шаге не сказано ничего, — здесь он молчит: пустой
|
|
26
|
+
# ход неотличим от хода, которому нечего было делать. Это известная его граница. Зелёный прогон
|
|
27
|
+
# он тоже не судит: за ним идёт своя работа — уборка и снятие черновика, — а не чужой шаг.
|
|
28
|
+
#
|
|
29
|
+
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, нехватке `jq`, отсутствии записи хода и повторном
|
|
30
|
+
# заходе ход РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
31
|
+
|
|
32
|
+
input="$(cat 2>/dev/null)"
|
|
33
|
+
[ -z "$input" ] && exit 0
|
|
34
|
+
|
|
35
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
36
|
+
|
|
37
|
+
# Повторный заход по тому же ходу не судится: гард сказал своё один раз и отпускает.
|
|
38
|
+
active="$(printf '%s' "$input" | jq -r '.stop_hook_active // false' 2>/dev/null)"
|
|
39
|
+
[ "$active" = "true" ] && exit 0
|
|
40
|
+
|
|
41
|
+
transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)"
|
|
42
|
+
[ -z "$transcript" ] && exit 0
|
|
43
|
+
[ -f "$transcript" ] || exit 0
|
|
44
|
+
|
|
45
|
+
# Открытие PR у каждого хостинга своё, и гард переносится между ними целиком: набор называет все
|
|
46
|
+
# три формы, а не ту, что стоит в этом дереве. Правка тела PR сюда не входит — она не открывает
|
|
47
|
+
# ничего.
|
|
48
|
+
opened_re='gh[^|;&]*pr[[:space:]]+create|api[^|;&]*-X[[:space:]]+POST[^|;&]*/pulls|glab[^|;&]*mr[[:space:]]+create|az[[:space:]]+repos[[:space:]]+pr[[:space:]]+create'
|
|
49
|
+
|
|
50
|
+
# Чтение прогона — второй случай чужого шага. Сам по себе он ничего не значит: конец прогона
|
|
51
|
+
# читают и затем, чтобы пойти чинить. Значит красный ответ, а он лежит не в команде, а в её
|
|
52
|
+
# выводе — там же, в записи хода, и сети для этого не нужно.
|
|
53
|
+
read_re='run[[:space:]]+(list|view|watch)|pipelines[[:space:]]+runs'
|
|
54
|
+
red_re='completed[[:space:]]+failure|"conclusion"[[:space:]]*:[[:space:]]*"failure"|conclusion:[[:space:]]*failure|completed with .failure.|run[[:space:]]+failed'
|
|
55
|
+
|
|
56
|
+
# Первое действие по следующей задаче. Заведение папки стоит здесь наравне с командами: работа
|
|
57
|
+
# по уже заведённому номеру начинается именно с неё. Правка кода в ветке того же PR действием
|
|
58
|
+
# по следующей задаче не считается — она чинит прежнюю, а не двигает работу дальше.
|
|
59
|
+
moved_re='task:new|task:move|checkout[[:space:]]+-b|docs/tasks/'
|
|
60
|
+
|
|
61
|
+
# Ход — это всё, что записано после последнего настоящего ввода владельца. Ответ инструмента
|
|
62
|
+
# приходит той же ролью, поэтому строки с `tool_result` вводом не считаются.
|
|
63
|
+
#
|
|
64
|
+
# Хвост в 400 строк: запись хода растёт всю сессию, а судится только последний ход.
|
|
65
|
+
verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r \
|
|
66
|
+
--arg opened "$opened_re" --arg moved "$moved_re" --arg read "$read_re" --arg red "$red_re" '
|
|
67
|
+
def is_input:
|
|
68
|
+
.type == "user"
|
|
69
|
+
and (((.message.content // []) | if type == "array"
|
|
70
|
+
then ([.[] | select(.type == "tool_result")] | length)
|
|
71
|
+
else 0 end) == 0);
|
|
72
|
+
|
|
73
|
+
(map(is_input) | rindex(true)) as $i
|
|
74
|
+
| (if $i == null then [] else .[$i:] end) as $turn
|
|
75
|
+
| [$turn[] | select(.type == "assistant") | (.message.content // [])[] | select(.type == "tool_use")] as $uses
|
|
76
|
+
| ($uses | map((.input.command // "")) | join("\n")) as $ran
|
|
77
|
+
# Ответ инструмента берётся текстом, а не в записи JSON: у той таб и кавычка уезжают
|
|
78
|
+
# экранированными, и образец по ним не попадает вовсе. Приходит он и строкой, и списком
|
|
79
|
+
# блоков — обе формы сводятся к одному тексту.
|
|
80
|
+
| ([$turn[] | select(.type == "user") | .message.content // [] | select(type == "array") | .[]
|
|
81
|
+
| select(.type == "tool_result") | .content
|
|
82
|
+
| if type == "string" then .
|
|
83
|
+
elif type == "array" then (map(if type == "object" then (.text // "") else tostring end) | join("\n"))
|
|
84
|
+
else tostring end] | join("\n")) as $out
|
|
85
|
+
| ($ran | test($opened; "i")) as $opened_pr
|
|
86
|
+
| (($ran | test($read; "i")) and ($out | test($red; "i"))) as $red_run
|
|
87
|
+
| ($ran | test($moved; "i")) as $went_on
|
|
88
|
+
| if $went_on then "pass"
|
|
89
|
+
elif $opened_pr then "owe:pr"
|
|
90
|
+
elif $red_run then "owe:run"
|
|
91
|
+
else "pass" end
|
|
92
|
+
' 2>/dev/null)"
|
|
93
|
+
|
|
94
|
+
case "$verdict" in
|
|
95
|
+
owe:pr) said="в этом ходе открыт PR" ;;
|
|
96
|
+
owe:run) said="в этом ходе прочитан красный прогон" ;;
|
|
97
|
+
*) exit 0 ;;
|
|
98
|
+
esac
|
|
99
|
+
|
|
100
|
+
reason="BLOCKED by waiting-turn-guard: ${said}, а действия по следующей задаче в нём нет ни одного. Ожидание чужого шага заходом не занимают: прогон, разбор и слияние идут на стороне и быстрее от взгляда не становятся.
|
|
101
|
+
|
|
102
|
+
Сказать «беру следующую задачу» — не то же самое, что взять её: фраза живёт до конца хода, а работа не двигается, и заметить это может только владелец.
|
|
103
|
+
|
|
104
|
+
Тем же ходом делается первое действие по следующей задаче — заведение задачи, ветки или папки:
|
|
105
|
+
|
|
106
|
+
npm run task:new -- --title '<Что не так>' --slug <slug>
|
|
107
|
+
git checkout -b <КЛЮЧ>-<номер>-<slug>
|
|
108
|
+
|
|
109
|
+
Конец прогона узнаётся возвратом фоновой команды, а не взглядом на страницу.
|
|
110
|
+
|
|
111
|
+
Гард судит один ход: следующий заход не отбивается."
|
|
112
|
+
|
|
113
|
+
jq -n --arg r "$reason" '{decision:"block",reason:$r}' 2>/dev/null \
|
|
114
|
+
|| printf '{"decision":"block","reason":"waiting-turn-guard: PR открыт — тем же ходом берётся следующая задача."}\n'
|
|
115
|
+
|
|
116
|
+
exit 0
|
package/assets/laws/delivery.md
CHANGED
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
очередь не попала, никто не видит, и работа за ней не планировалась.
|
|
11
11
|
- **Правка попадает в главную ветку только через отдельную ветку.** Прямая запись в главную
|
|
12
12
|
лишает правку и обсуждения, и возможности откатить её одним движением.
|
|
13
|
+
- **В очереди работ стоят задачи, а не PR о них.** У задачи и её PR один номер и одна судьба,
|
|
14
|
+
поэтому вторая карточка о той же работе ничего не добавляет — она удваивает очередь и врёт о
|
|
15
|
+
её длине. Читают очередь затем, чтобы увидеть, что сделано и что осталось; PR отвечает на
|
|
16
|
+
другой вопрос — как именно сделано, — и попадают в него из карточки задачи, где связь с ним
|
|
17
|
+
и так стоит. Карточка PR при этом живёт своей жизнью: закрывается позже задачи, висит в
|
|
18
|
+
очереди после слияния и остаётся в ней навсегда, потому что колонки под неё нет.
|
|
19
|
+
- **Проверка не гоняет того, что правка не может сломать.** Набор, одинаковый для любой правки,
|
|
20
|
+
выглядит строгим, а работает наоборот: прогон, который длится вдесятеро дольше нужного, учат
|
|
21
|
+
не ждать, а обходить. Состав набора выводится из состава правки — из того, что она задела, а
|
|
22
|
+
не из того, кем она названа; правка, не тронувшая ни строки кода, не собирает образов и не
|
|
23
|
+
снимает кадров. Пропущенное при этом называется пропущенным: молча выпавший шаг читается как
|
|
24
|
+
пройденный.
|
|
13
25
|
- **У задачи одна ветка, у ветки одна задача.** Откат снимает всё, что въехало этой веткой,
|
|
14
26
|
разом: две задачи в ней откатятся только вместе, а задача, въехавшая двумя ветками, после
|
|
15
27
|
отката одной останется наполовину сделанной — и в очереди работ этого не видно. Работа,
|
|
@@ -71,6 +83,22 @@
|
|
|
71
83
|
иначе «сошлось» значит в этих двух местах разное.
|
|
72
84
|
- **Документ едет вместе с правкой, которую он описывает.** Ни сборка, ни проверки текстов
|
|
73
85
|
не читают, поэтому расхождение копится молча и потом выглядит действующей справкой.
|
|
86
|
+
- **Работа, меняющая код, кончается открытым PR.** PR — единственное место, где человек видит
|
|
87
|
+
правку целиком, отвечает на неё и вливает её; коммит в ветке и запушенная ветка этого места
|
|
88
|
+
не заменяют. Пока PR не открыт, работа сделанной не считается, сколько бы её ни было в
|
|
89
|
+
истории ветки: разбор по ней невозможен, а человек о ней не знает. Открывается PR тем же
|
|
90
|
+
ходом, которым исполнитель говорит, что работу отдаёт, — а не следующим заходом и не по
|
|
91
|
+
напоминанию.
|
|
92
|
+
- **PR, не готовый к слиянию, помечается черновиком.** Открытый PR читается как приглашение
|
|
93
|
+
влить, и человек нажимает слияние, не спрашивая, кончилась ли работа. Черновик разводит два
|
|
94
|
+
состояния, которые иначе выглядят одинаково: правка выложена на обозрение — и правка готова
|
|
95
|
+
поехать в главную ветку. Помечается им всё, что ждёт прогона, доработки или ответа на
|
|
96
|
+
вопрос; вопрос при этом задаётся в самом PR, а не остаётся в голове исполнителя.
|
|
97
|
+
- **Снятие черновика — отдельный ход, и им исполнитель отвечает за готовность.** Черновик
|
|
98
|
+
снимается тогда, когда проверки пройдены, доработок не осталось и работа сходится с тем,
|
|
99
|
+
ради чего заводилась задача. Пока он стоит, молчание исполнителя значит «ещё не готово», и
|
|
100
|
+
человек ничего не должен переспрашивать; после снятия оно значит «можно вливать», и цена
|
|
101
|
+
ошибки здесь — правка в главной ветке.
|
|
74
102
|
- **PR о сделанном остаётся верным до самого слияния.** Он описывает дерево на день, когда
|
|
75
103
|
его написали, а разбора ждёт днями: за это время главная ветка вливается в ветку, и
|
|
76
104
|
утверждение PR о соседних файлах становится неправдой молча — тел PR не читает ни
|
|
@@ -81,6 +109,13 @@
|
|
|
81
109
|
человека и только про названный PR; молчание разрешением не бывает, а слово, сказанное об
|
|
82
110
|
одном PR, на следующий не переносится. Иначе разбор проходит тот, кого разбирают, и
|
|
83
111
|
очередь PR выглядит разобранной, не будучи ею.
|
|
112
|
+
- **Требование, стоящее перед необратимым шагом, стоит там, где этот шаг совершают.** Гард на
|
|
113
|
+
машине исполнителя судит его команды и молчит о том же действии, совершённом кнопкой у
|
|
114
|
+
хостинга: обход выходит не намеренным, а незамеченным — нажавший не знает, что чего-то не
|
|
115
|
+
хватало. Требование либо переносится туда, где нажимают, либо объявляется тому, кто нажимает,
|
|
116
|
+
до нажатия. Иначе оно держится не собой, а тем, что необратимый шаг каждый раз делает тот же
|
|
117
|
+
человек: папка закрытой задачи так и уехала в главную ветку вместе со своей договорённостью, и
|
|
118
|
+
вынимать её пришлось отдельной задачей.
|
|
84
119
|
- **Слияние в главную ветку ещё не означает, что правка доехала.** Отказ выкатки не трогает ни
|
|
85
120
|
задачу, ни очередь работ, поэтому расхождение главной ветки с тем, что работает, обязано быть
|
|
86
121
|
видно там, где очередь читают. Иначе следующие работы вливаются поверх поломки, которую не
|
|
@@ -77,3 +77,21 @@
|
|
|
77
77
|
- **Работа, которая переносит решения, называет для каждого, куда оно ушло.** Иначе по
|
|
78
78
|
описанию прошлого не отличить решение, ставшее правилом, от решения, потерянного при
|
|
79
79
|
переносе: оба выглядят одинаково — записью, на которую никто не ссылается.
|
|
80
|
+
- **Текст, раздаваемый наружу, судится не слабее своей копии у потребителя.** Требование,
|
|
81
|
+
стоящее к копии и не стоящее к источнику, находит промах у того, кто его не делал и починить
|
|
82
|
+
не может: до потребителя промах доезжает целым, а краснеет уже там.
|
|
83
|
+
- **Редакция текста, которую это дерево не выбрало, судится наравне с выбранной.**
|
|
84
|
+
Непрочитанная редакция расходится с прочитанной молча, и узнаёт об этом первый, кто её
|
|
85
|
+
выберет, — то есть тот, у кого нет ни истории расхождения, ни повода его искать.
|
|
86
|
+
- **Набор обязательных разделов объявлен отдельно, и образец ему не хозяин.** Образец —
|
|
87
|
+
черновик для того, кто заводит текст, и стареет он первым. Набор, выведенный из образца, либо
|
|
88
|
+
объявляет расхождением весь корпус разом, либо не замечает ничего.
|
|
89
|
+
- **Требование, которого никто не формулировал, молчит, а не отказывает.** Отказ на предмете
|
|
90
|
+
без объявленного требования гасят списком исключений, а список исключений через месяц
|
|
91
|
+
становится рабочим путём — и гасит вместе с шумом то, ради чего проверка заводилась.
|
|
92
|
+
- **Два текста об одном либо говорят одно, либо один из них неправ.** Согласие текстов между
|
|
93
|
+
собой не следует ни из целостности ссылок, ни из полноты разделов: оба проходят любую такую
|
|
94
|
+
проверку, а исполнитель берёт тот, который прочитал раньше. Ищется это чтением — считать
|
|
95
|
+
здесь нечего.
|
|
96
|
+
- **Изображение правится тем же изменением, что и текст, который оно изображает.** Разойдясь,
|
|
97
|
+
схема и проза остаются читаемыми обе, и первым это замечает тот, кто пошёл по схеме.
|
|
@@ -13,6 +13,15 @@
|
|
|
13
13
|
- **Пробел закрывается вопросом владельцу, а не догадкой.** Догадка неотличима от знания:
|
|
14
14
|
она попадает в работу молча и обнаруживается только при приёмке, когда переделывать дороже
|
|
15
15
|
всего.
|
|
16
|
+
- **Работа, объявленная сборкой по образцу, начинается с чтения самого образца.** Пересказ
|
|
17
|
+
образца образцом не является: по нему собирается понимание того, кто пересказывал, и
|
|
18
|
+
расхождение всплывает на приёмке целой работой, а не строкой. Читается та часть образца,
|
|
19
|
+
которую работа повторяет, и читается целиком — об устройстве чужого дерева по одному его
|
|
20
|
+
файлу не судят.
|
|
21
|
+
- **Образец, названный однажды, доступен каждому заходу работы.** Где он лежит, записано
|
|
22
|
+
там, где заход найдёт это без владельца. Иначе второй заход собирает по памяти первого,
|
|
23
|
+
третий — по пересказу второго, и к четвёртому от образца не остаётся ничего, кроме слова
|
|
24
|
+
«образец».
|
|
16
25
|
- **Вопрос, у которого есть очевидный ответ, работу не останавливает.** Исполнитель называет
|
|
17
26
|
допущение, идёт дальше и записывает его туда же, где идёт работа. Останавливает только тот
|
|
18
27
|
пробел, при котором любая догадка делает работу опасной или бесполезной. Вопрос, заданный
|
|
@@ -136,6 +145,22 @@
|
|
|
136
145
|
- **Работа, отданная на разбор, освобождает исполнителя, а не останавливает его.** Отданное на
|
|
137
146
|
разбор ждёт владельца, а не машину: следующая задача эпика берётся тем же движением, которым
|
|
138
147
|
предыдущая ушла на разбор.
|
|
148
|
+
- **Ожидание машины работой не занимают.** Проверка, идущая на стороне, не спрашивает
|
|
149
|
+
исполнителя ни о чём и не идёт быстрее оттого, что он на неё смотрит. Пока она идёт, работа
|
|
150
|
+
продолжается: берётся следующая задача, а к проверке возвращаются тем ходом, которым читают
|
|
151
|
+
её конец. Заход, проведённый в ожидании, стоит ровно столько же, сколько заход, в котором
|
|
152
|
+
сделана задача, — и не даёт ничего.
|
|
153
|
+
- **Ожидание, которое всё-таки останавливает работу, называется владельцу отдельно и прямо.**
|
|
154
|
+
Есть случаи, где дальше и вправду не пройти: следующая задача стоит на неразобранной, или
|
|
155
|
+
правка ждёт решения, которого нет ни у кого, кроме владельца. Тогда исполнитель говорит три
|
|
156
|
+
вещи — что именно стоит, чего оно ждёт и что владелец может с этим сделать: разобрать работу
|
|
157
|
+
первой или снять ожидание своим словом. Сказанное вперемешку с отчётом о сделанном не
|
|
158
|
+
читается: остановка называется отдельно от всего остального.
|
|
159
|
+
- **Разбор закрытой работы идёт своим ходом и работу не задерживает.** Он смотрит на то, что
|
|
160
|
+
видно только заходу, который работу вёл, поэтому пропустить его нельзя; но и держать ради
|
|
161
|
+
него следующую задачу незачем — он ничего не спрашивает у исполнителя, пока идёт. Его находки
|
|
162
|
+
записываются туда, где их найдут после слияния работы, и показываются владельцу целиком, а не
|
|
163
|
+
уезжают наружу сами: что из них станет правкой, решает он.
|
|
139
164
|
- **Отдав работу на разбор, исполнитель называет, чего ждёт и что сделает следом.** Владелец
|
|
140
165
|
видит не голову исполнителя, а страницу работы: зелёная проверка и доступное действие
|
|
141
166
|
читаются как «всё кончено». Названное вслух ожидание — единственное, что отличает «жду
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: admin-lists-screen
|
|
3
3
|
kind: pattern
|
|
4
4
|
rule: lists
|
|
5
|
-
description: Паттерн правила lists. Брать при сборке или правке списочного экрана админки — готовый порядок блоков, разметка <префикс>-table, клик по строке, меню строки с
|
|
5
|
+
description: Паттерн правила lists. Брать при сборке или правке списочного экрана админки — готовый порядок блоков, разметка <префикс>-table, клик по строке, меню строки с колонкой действий и предикатом строки, сортируемый заголовок, слоты тулбара, тост отказа.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Собрать списочный экран
|
|
@@ -25,7 +25,7 @@ description: Паттерн правила lists. Брать при сборке
|
|
|
25
25
|
<header rtElem="header">
|
|
26
26
|
<!-- div rtElem="header-main" c h1 rtElem="title" + p rtElem="hint" -->
|
|
27
27
|
<<префикс>-toolbar>
|
|
28
|
-
<!--
|
|
28
|
+
<!-- <префикс>ToolbarLeft / <префикс>ToolbarRight -->
|
|
29
29
|
<div rtElem="scroll">
|
|
30
30
|
<!-- overflow-x: auto -->
|
|
31
31
|
<<префикс>-table rtElem="table">
|
|
@@ -42,9 +42,9 @@ description: Паттерн правила lists. Брать при сборке
|
|
|
42
42
|
## Таблица
|
|
43
43
|
|
|
44
44
|
```html
|
|
45
|
-
<<префикс>-table #rowsTable="
|
|
46
|
-
| transloco" [tableId]="tableId" [dataSource]="rows()" [columnsConfig]="columnsConfig()"
|
|
47
|
-
[loading]="loading()">
|
|
45
|
+
<<префикс>-table #rowsTable="<префикс>Table" rtElem="table" clickable [ariaLabel]="'recordsTableAria' | transloco"
|
|
46
|
+
[emptyMessage]="'recordsEmpty' | transloco" [tableId]="tableId" [dataSource]="rows()" [columnsConfig]="columnsConfig()"
|
|
47
|
+
[rowHasActions]="hasRowActions" [loading]="loading()">
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
- `tableId` — ключ, под которым хранится выбор столбцов; он же уходит в асайд настроек.
|
|
@@ -57,8 +57,8 @@ description: Паттерн правила lists. Брать при сборке
|
|
|
57
57
|
<tr
|
|
58
58
|
*cdkRowDef="let row; columns: rowsTable.displayedColumns()"
|
|
59
59
|
cdk-row
|
|
60
|
-
qa-dataid="
|
|
61
|
-
|
|
60
|
+
qa-dataid="records-row"
|
|
61
|
+
<префикс>TableRow
|
|
62
62
|
(activated)="openAside(row)"></tr>
|
|
63
63
|
```
|
|
64
64
|
|
|
@@ -67,13 +67,24 @@ description: Паттерн правила lists. Брать при сборке
|
|
|
67
67
|
## Меню строки
|
|
68
68
|
|
|
69
69
|
```html
|
|
70
|
-
|
|
70
|
+
<<префикс>-table … [showRowActions]="true" [rowHasActions]="hasRowActions" [loading]="loading()">
|
|
71
|
+
<ng-template <префикс>TableRowActions let-row [<префикс>TableRowActionsRowType]="rows()"></ng-template>
|
|
71
72
|
```
|
|
72
73
|
|
|
73
74
|
```typescript
|
|
74
|
-
protected readonly hasRowActions
|
|
75
|
+
protected readonly hasRowActions: I<Префикс>Table.RowActionsPredicate<IRecord.Row> = recordRowHasActions;
|
|
75
76
|
```
|
|
76
77
|
|
|
78
|
+
Входа два, и они не заменяют друг друга. `showRowActions` заводит саму колонку действий — по
|
|
79
|
+
умолчанию он опущен, и без него таблица рисует одни объявленные столбцы: ни шаблон действий, ни
|
|
80
|
+
предикат колонки не добавляют. `rowHasActions` решает, показывать ли кнопку у конкретной
|
|
81
|
+
строки, и колонки не заводит вовсе. Экран ролей так и вышел с четырьмя столбцами и
|
|
82
|
+
недостижимыми действиями: сборка, линт и юниты на правилах строки при этом зелёные, а нашёл
|
|
83
|
+
это прогон сквозной спеки.
|
|
84
|
+
|
|
85
|
+
Ячейка действий скрыта, пока указатель не на строке, — сквозная спека наводит на строку до
|
|
86
|
+
нажатия.
|
|
87
|
+
|
|
77
88
|
Доступность действия лежит полем строки (`canConfirm`, `canReject`), а не вызовом метода
|
|
78
89
|
компонента. Действие, которого записи нельзя сделать, из меню убирается целиком. Необратимое
|
|
79
90
|
несёт `danger`, `confirmTitle` и `confirmMessage` с последствием — не «Вы уверены?», а что
|
|
@@ -82,7 +93,7 @@ protected readonly hasRowActions = (row: IBooking.State): boolean => row.canConf
|
|
|
82
93
|
## Сортируемый заголовок
|
|
83
94
|
|
|
84
95
|
```html
|
|
85
|
-
<th *cdkHeaderCellDef cdk-header-cell
|
|
96
|
+
<th *cdkHeaderCellDef cdk-header-cell <префикс>SortHeader="createdAt">{{ 'recordsCreatedAt' | transloco }}</th>
|
|
86
97
|
```
|
|
87
98
|
|
|
88
99
|
Колонка помечается `sortable: true` в `columnsConfig`. Заголовок переключает сортировку по
|
|
@@ -95,8 +106,8 @@ protected readonly hasRowActions = (row: IBooking.State): boolean => row.canConf
|
|
|
95
106
|
|
|
96
107
|
## Тулбар
|
|
97
108
|
|
|
98
|
-
Тулбар поделён на две части слотами: `
|
|
99
|
-
`
|
|
109
|
+
Тулбар поделён на две части слотами: `<префикс>ToolbarLeft` — то, что меняет выборку,
|
|
110
|
+
`<префикс>ToolbarRight` — действия над списком. Своей раскладки внутри тулбара экран не заводит.
|
|
100
111
|
|
|
101
112
|
Левый слот — фильтры и поиск. Правый — иконки `<префикс>-icon-button variant="primary"` с парой
|
|
102
113
|
`tooltip` + `ariaLabel` одного текста: обновление (`sync`), настройки столбцов (`sliders-v`),
|
|
@@ -105,7 +116,7 @@ protected readonly hasRowActions = (row: IBooking.State): boolean => row.canConf
|
|
|
105
116
|
## Отказ загрузки
|
|
106
117
|
|
|
107
118
|
```typescript
|
|
108
|
-
this.#notifications.error(this.#transloco.translate(this.#store.errorKey() ?? '
|
|
119
|
+
this.#notifications.error(this.#transloco.translate(this.#store.errorKey() ?? 'recordsLoadFailed'));
|
|
109
120
|
```
|
|
110
121
|
|
|
111
122
|
Ключ читается сразу после запроса, а не подпиской на сигнал стора: стор делят список и панель
|
|
@@ -118,7 +129,7 @@ this.#notifications.error(this.#transloco.translate(this.#store.errorKey() ?? 'b
|
|
|
118
129
|
npx nx build admin
|
|
119
130
|
```
|
|
120
131
|
|
|
121
|
-
Продовая сборка обязательна: без `[
|
|
132
|
+
Продовая сборка обязательна: без `[<префикс>TableRowActionsRowType]` тип `let-row` выводится как
|
|
122
133
|
`unknown`, и падает только она — юниты и дев-сервер проходят.
|
|
123
134
|
|
|
124
135
|
## Частые промахи
|
|
@@ -65,7 +65,7 @@ description: Паттерн правила navigation. Брать при зав
|
|
|
65
65
|
- Обход одного верхнего ряда при поиске владельца адреса: разделы обходятся вместе с пунктами
|
|
66
66
|
их панелей, иначе вложенный экран остаётся без гейтинга.
|
|
67
67
|
- Подсказка у доступного пункта: она дословно повторяет подпись рядом и не добавляет ничего.
|
|
68
|
-
- `
|
|
68
|
+
- `<префикс>PopoverTrigger` не поставлен явно: директива попапа по умолчанию открывается нажатием, и
|
|
69
69
|
два соседних элемента одного ряда ведут себя по-разному.
|
|
70
70
|
- Переезд адреса без правки сквозных спек: они ходят по адресам, и прогон станет красным.
|
|
71
71
|
- Иконка, подобранная «похожая»: отсутствующая добавляется в спрайт и в `<префикс>-icon-names.ts`.
|
|
@@ -77,7 +77,7 @@ export class ComponentNameComponent {
|
|
|
77
77
|
## `qa-dataid` — на каждый интерактивный элемент
|
|
78
78
|
|
|
79
79
|
```html
|
|
80
|
-
<button
|
|
80
|
+
<button <префикс>Button qa-dataid="calendar-retry-prices" type="button" (click)="retryPrices.emit()">Повторить</button>
|
|
81
81
|
<div rtElem="grid" qa-dataid="admin-calendar-grid"></div>
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -132,5 +132,7 @@ constructor() {
|
|
|
132
132
|
обводку фокуса у края прокрутки.
|
|
133
133
|
- Панель, остающаяся открытой после успеха, не сбросила нетронутость (`markAsPristine`) —
|
|
134
134
|
вопрос о правках задаётся сразу после записи.
|
|
135
|
-
- Отключённые поля ввода вместо данных: запись, которую только смотрят, показывается
|
|
136
|
-
|
|
135
|
+
- Отключённые поля ввода вместо данных: запись, которую только смотрят, показывается готовым
|
|
136
|
+
списком свойств кита — `<префикс>-detail-list`, `<префикс>-info-item`. Своя разметка на `<dl>`
|
|
137
|
+
идёт последней и только как разовое отступление: она и есть отход от общего вида, а решает
|
|
138
|
+
его владелец, — перечень, ставящий её первой, учит обходить готовое раньше, чем спросить.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: git-workflow-commit
|
|
3
3
|
kind: pattern
|
|
4
4
|
rule: git-workflow
|
|
5
|
-
description: Паттерн правила git-workflow для дерева в Azure DevOps. Брать на заведение рабочего элемента, ветки, коммит, пуш и создание PR — заведение элемента со всеми шагами, перевод по состояниям, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, привязка PR к элементу, ревьювер, исполнитель и метки, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
|
|
5
|
+
description: Паттерн правила git-workflow для дерева в Azure DevOps. Брать на заведение рабочего элемента, ветки, коммит, пуш и создание PR — заведение элемента со всеми шагами, перевод по состояниям, слияние двух задач в одну, сверка очереди работ, работа от учётной записи машинной работы, формат заголовка, привязка PR к элементу, ревьювер, исполнитель и метки, образец тела PR с разделом об оставшемся шаге, чеклист проверок до публикации, обход требования документа. Не брать для миграций и перезапуска прода — это паттерны git-workflow-migration и git-workflow-restart.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Ветка, коммит и PR
|
|
@@ -169,6 +169,35 @@ PR [86] Письмо владельцу с незаполненным ад
|
|
|
169
169
|
Тип и область — `fix(site):`, `docs(common):` — в заголовок PR не идут: это формат заголовка
|
|
170
170
|
коммита, и там его сверяет `commitlint`.
|
|
171
171
|
|
|
172
|
+
## Не готовое к слиянию открывается черновиком
|
|
173
|
+
|
|
174
|
+
Правка кода отдаётся человеку открытым PR: запушенная ветка ему не показывается нигде. Открытый
|
|
175
|
+
PR при этом читается как приглашение влить, поэтому у незаконченной работы он открывается
|
|
176
|
+
черновиком — завершение у черновика хостинг блокирует сам:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
AZURE_DEVOPS_EXT_PAT="$TOKEN" az repos pr create --draft true --title '[<КЛЮЧ>-86] …' \
|
|
180
|
+
--description "$(cat тело.md)"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Конвейер проверок у черновика по умолчанию не запускается: молчание прогона за зелёный прогон
|
|
184
|
+
не принимается, и набор гоняется на своей машине либо запуском вручную.
|
|
185
|
+
|
|
186
|
+
Черновиком идёт всё, что ждёт прогона конвейера, доработки или ответа на вопрос. Вопрос
|
|
187
|
+
задаётся в самом PR, а не остаётся в голове исполнителя: человек читает PR, а не переписку
|
|
188
|
+
захода.
|
|
189
|
+
|
|
190
|
+
Снимается черновик отдельным вызовом, и это тот самый ход, которым исполнитель говорит, что
|
|
191
|
+
решение готово:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
AZURE_DEVOPS_EXT_PAT="$TOKEN" az repos pr update --id 86 --draft false
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
До снятия молчание исполнителя значит «ещё не готово», после — «можно вливать». Снятие
|
|
198
|
+
черновика и просьба влить идут одним ходом: снятый черновик, о котором человеку не сказали,
|
|
199
|
+
ждёт разбора ровно так же, как не снятый.
|
|
200
|
+
|
|
172
201
|
## PR привязывается к элементу при создании
|
|
173
202
|
|
|
174
203
|
Привязка задаётся флагом, а не правкой после: у токена может не быть права править чужой
|
|
@@ -197,6 +226,46 @@ az repos pr update --id 205 --description "$(cat тело.md)"
|
|
|
197
226
|
Правка описания переписывает его целиком. Тело перечитывается всякий раз, когда в ветку что-то
|
|
198
227
|
влилось после публикации: PR утверждает про дерево, а дерево с тех пор изменилось.
|
|
199
228
|
|
|
229
|
+
## Образец тела PR
|
|
230
|
+
|
|
231
|
+
Четыре раздела, и порядок между ними один: строка связи, что сделано, чем подтверждено,
|
|
232
|
+
оставшийся шаг. Раздел, которому нечего сказать, пишется словами — пустой заголовок и снятый
|
|
233
|
+
заголовок читаются одинаково, а значат разное.
|
|
234
|
+
|
|
235
|
+
```markdown
|
|
236
|
+
Закрывает рабочий элемент 86.
|
|
237
|
+
|
|
238
|
+
## Что сделано
|
|
239
|
+
|
|
240
|
+
- <правка, названная тем, что она меняет для читателя, а не тем, какие файлы задела>
|
|
241
|
+
|
|
242
|
+
## Чем подтверждено
|
|
243
|
+
|
|
244
|
+
- <проверка>: <её вывод одной строкой>
|
|
245
|
+
- Не гонялось: <что в набор не вошло и почему>
|
|
246
|
+
|
|
247
|
+
## Оставшийся шаг
|
|
248
|
+
|
|
249
|
+
После одобрения ветка получает ещё один коммит — разбор папки задачи, — и только потом
|
|
250
|
+
вливается. До этого коммита вливать рано: папка уедет в главную ветку неразобранной.
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
|
|
254
|
+
— в тот ход, которым папка разбирается и снимается черновик:
|
|
255
|
+
|
|
256
|
+
```markdown
|
|
257
|
+
## Оставшийся шаг
|
|
258
|
+
|
|
259
|
+
Не осталось: папка задачи разобрана коммитом `<sha>`, черновик снят. Можно вливать.
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
|
|
263
|
+
сказанное владельцу вслух живёт до следующей реплики, а тело лежит у самой кнопки. Одно другого
|
|
264
|
+
не отменяет — порядок обоих сообщений владельцу описывает паттерн закрытия работы.
|
|
265
|
+
|
|
266
|
+
Проверить тело машиной нечем: ни одна сверка его не читает, а хостинг спрашивает только про
|
|
267
|
+
заголовок. Держится образец тем, кто пишет тело, — как и слова вслух.
|
|
268
|
+
|
|
200
269
|
## Состояние PR читается, а не додумывается
|
|
201
270
|
|
|
202
271
|
Команды правки отвечают нулевым кодом и тогда, когда ничего не сделали. Поэтому после них PR
|
|
@@ -244,7 +313,10 @@ npm run task:move -- 86 in-review
|
|
|
244
313
|
`browser-verification-measure`.
|
|
245
314
|
9. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** —
|
|
246
315
|
паттерн `seo-verify`.
|
|
247
|
-
10. **PR привязан к рабочему элементу**, ревьювер и исполнитель
|
|
316
|
+
10. **PR привязан к рабочему элементу**, ревьювер и исполнитель стоят, а тело собрано по
|
|
317
|
+
образцу — разделы «Что сделано», «Чем подтверждено» и «Оставшийся шаг». Раздел оставшегося
|
|
318
|
+
шага к этому моменту говорит, что шагов не осталось: черновик снимается после разбора
|
|
319
|
+
папки, а не до него.
|
|
248
320
|
11. **Заголовок PR несёт номер элемента и называет работу сделанной:** `[<номер>] <Что
|
|
249
321
|
сделано>`, тем же номером, что стоит у элемента и в имени ветки.
|
|
250
322
|
12. **Очередь работ сходится** — `npm run check:board`.
|