@rt-tools/agent-kit 0.5.1 → 0.5.3
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 +102 -6
- package/assets/commands/agent-kit-digest.md +83 -0
- package/assets/commands/skill-curator.md +33 -1
- package/assets/defaults/gate-map.sh +2 -0
- package/assets/defaults/project.sh +12 -1
- package/assets/docs/GLOSSARY.md +3 -0
- package/assets/hooks/docs-guard.sh +18 -1
- package/assets/hooks/git-guard-delivery.sh +30 -3
- package/assets/hooks/git-guard-main.sh +8 -0
- package/assets/hooks/git-guard-push-tests.sh +8 -1
- package/assets/hooks/grill-gate.sh +38 -16
- package/assets/hooks/lint-after-edit.sh +10 -3
- package/assets/hooks/observe.sh +90 -0
- package/assets/hooks/postmortem-guard.sh +92 -0
- package/assets/hooks/profile-check.sh +43 -0
- package/assets/hooks/qa-dataid-guard.sh +9 -2
- package/assets/hooks/reuse-first-guard.sh +9 -2
- package/assets/hooks/skill-gate.sh +15 -0
- package/assets/hooks/skill-loaded.sh +7 -0
- package/assets/hooks/task-context-load.sh +16 -2
- package/assets/hooks/task-flow-guard.sh +9 -2
- package/assets/hooks/window-fill-guard.sh +8 -1
- package/assets/laws/project-documentation.md +5 -0
- package/assets/laws/verifiability.md +9 -0
- package/assets/laws/work-conduct.md +39 -0
- package/assets/patterns/git-workflow-commit.azure.md +16 -12
- package/assets/patterns/git-workflow-commit.github.md +16 -12
- package/assets/patterns/git-workflow-commit.gitlab.md +16 -12
- package/assets/patterns/task-flow-resume.md +12 -0
- package/assets/patterns/task-flow-start.md +36 -2
- package/assets/rules/git-workflow.azure.md +15 -0
- package/assets/rules/git-workflow.github.md +15 -0
- package/assets/rules/git-workflow.gitlab.md +15 -0
- package/assets/rules/spec-driven.md +6 -0
- package/assets/rules/task-flow.md +24 -3
- package/assets/skills/agent-kit.md +32 -0
- package/assets/templates/postmortem.md +32 -0
- package/assets/templates/proposal.md +39 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +50 -1
- package/bin/agent-kit.js.map +1 -1
- package/lib/catalog.d.ts +33 -0
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +55 -1
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts +41 -0
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +314 -3
- package/lib/commands.js.map +1 -1
- package/lib/config.d.ts +8 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +4 -0
- package/lib/config.js.map +1 -1
- package/lib/observations.d.ts +72 -0
- package/lib/observations.d.ts.map +1 -0
- package/lib/observations.js +126 -0
- package/lib/observations.js.map +1 -0
- package/lib/proposals.d.ts +48 -0
- package/lib/proposals.d.ts.map +1 -0
- package/lib/proposals.js +111 -0
- package/lib/proposals.js.map +1 -0
- package/lib/submit.d.ts +24 -0
- package/lib/submit.d.ts.map +1 -0
- package/lib/submit.js +26 -0
- package/lib/submit.js.map +1 -0
- package/lib/sync.d.ts +9 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +2 -1
- package/lib/sync.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.5.3.tgz +0 -0
- package/rt-tools-agent-kit-0.5.1.tgz +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Запись наблюдений о слое правил. НЕ гард: объявления `rt-hook:` у него нет, к событиям агента
|
|
3
|
+
# он не подключается. Его источают гарды — тем же приёмом, каким гейт источает карту.
|
|
4
|
+
#
|
|
5
|
+
# Зачем он есть. Правки в тексты пакета шли из головы того, кто их пишет: чем из разложенного
|
|
6
|
+
# пользуются каждый день, чем не пользовались ни разу и обо что спотыкаются по второму кругу,
|
|
7
|
+
# пакету было неизвестно. Часть данных при этом уже собиралась и выбрасывалась — запись загрузок
|
|
8
|
+
# жила во временном каталоге и гибла со сжатием контекста.
|
|
9
|
+
#
|
|
10
|
+
# ЧТО ЗАПИСЫВАЕТСЯ. Только имена ресурсов пакета и счётчики: имя правила или гарда, род события,
|
|
11
|
+
# род файла, версия пакета и признак сессии. Ни путей дерева, ни имён его доменов, ни имени
|
|
12
|
+
# самого дерева — и держится это не памятью зовущего, а `rt_observe_clean`: значение со слэшем
|
|
13
|
+
# не пишется вовсе. Наблюдение уезжает потом в чужой репозиторий, и запрет называть чужое дерево
|
|
14
|
+
# обязан держаться конструкцией.
|
|
15
|
+
#
|
|
16
|
+
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ. Наблюдение — побочная работа гарда, и любая её поломка молча пропускает
|
|
17
|
+
# действие: недоступный каталог, отсутствие `date`, полный диск. Гард, упавший на записи
|
|
18
|
+
# наблюдения, останавливал бы работу ради статистики.
|
|
19
|
+
|
|
20
|
+
# Значение, годное к записи. Путь не выносится ни при каких обстоятельствах, остальное чистится
|
|
21
|
+
# до имени и обрезается: длинное значение в наблюдении не значит ничего, кроме утечки.
|
|
22
|
+
rt_observe_clean() {
|
|
23
|
+
case "$1" in
|
|
24
|
+
*/*) return 0 ;;
|
|
25
|
+
esac
|
|
26
|
+
printf '%s' "$1" | LC_ALL=C tr -cd 'A-Za-z0-9._:-' | cut -c1-48
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Признак сессии: считается по её имени и обратно не восстанавливается. Нужен, чтобы сводка
|
|
30
|
+
# знала число заходов, а не только число событий.
|
|
31
|
+
rt_observe_session() {
|
|
32
|
+
printf '%s' "$1" | cksum 2>/dev/null | cut -d' ' -f1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Версия пакета, разложившего этот файл. Стоит в шапке, которую ставит раскладка; в исходниках
|
|
36
|
+
# пакета шапки нет, и там версия — `dev`.
|
|
37
|
+
rt_observe_version() {
|
|
38
|
+
local found
|
|
39
|
+
found="$(sed -n 's/^# rt-kit v\([^ ]*\) .*/\1/p' "${BASH_SOURCE[0]}" 2>/dev/null | head -1)"
|
|
40
|
+
printf '%s' "${found:-dev}"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Каталог наблюдений этого дерева. Пустая строка — записи не будет.
|
|
44
|
+
rt_observe_dir() {
|
|
45
|
+
local root="${CLAUDE_PROJECT_DIR:-.}" config
|
|
46
|
+
config="$root/.claude/rt-kit.json"
|
|
47
|
+
# Выключатель дерева гасит запись целиком, а не частями: пакет стоит и у тех, о ком мы не
|
|
48
|
+
# знаем. Нечитаемая настройка выключателем не считается — иначе сломанный JSON тихо
|
|
49
|
+
# выключал бы наблюдения, и понять это было бы нечем.
|
|
50
|
+
if [ -f "$config" ] && command -v jq >/dev/null 2>&1; then
|
|
51
|
+
[ "$(jq -r 'if .observe == false then "off" else "on" end' "$config" 2>/dev/null)" = "off" ] && return 0
|
|
52
|
+
fi
|
|
53
|
+
printf '%s' "$root/.claude/rt-kit/observations"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Одно наблюдение: род события и пары `ключ=значение`. Ключ `sid` хешируется, остальные
|
|
57
|
+
# чистятся. Пустое значение поля не заводит.
|
|
58
|
+
#
|
|
59
|
+
# rt_note gate-deny res=styling-bem kind=scss sid="$sid"
|
|
60
|
+
rt_note() {
|
|
61
|
+
local kind="$1" dir day stamp line pair key value
|
|
62
|
+
[ -n "$kind" ] || return 0
|
|
63
|
+
shift
|
|
64
|
+
|
|
65
|
+
dir="$(rt_observe_dir)"
|
|
66
|
+
[ -n "$dir" ] || return 0
|
|
67
|
+
mkdir -p "$dir" 2>/dev/null || return 0
|
|
68
|
+
|
|
69
|
+
day="$(date -u +%Y-%m-%d 2>/dev/null)" || return 0
|
|
70
|
+
stamp="$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null)" || return 0
|
|
71
|
+
[ -n "$day" ] || return 0
|
|
72
|
+
|
|
73
|
+
line="{\"t\":\"$stamp\",\"ev\":\"$(rt_observe_clean "$kind")\""
|
|
74
|
+
for pair in "$@"; do
|
|
75
|
+
key="$(rt_observe_clean "${pair%%=*}")"
|
|
76
|
+
value="${pair#*=}"
|
|
77
|
+
[ -n "$key" ] || continue
|
|
78
|
+
if [ "$key" = "sid" ]; then
|
|
79
|
+
value="$(rt_observe_session "$value")"
|
|
80
|
+
else
|
|
81
|
+
value="$(rt_observe_clean "$value")"
|
|
82
|
+
fi
|
|
83
|
+
[ -n "$value" ] || continue
|
|
84
|
+
line="$line,\"$key\":\"$value\""
|
|
85
|
+
done
|
|
86
|
+
line="$line,\"v\":\"$(rt_observe_version)\"}"
|
|
87
|
+
|
|
88
|
+
printf '%s\n' "$line" >> "$dir/$day.jsonl" 2>/dev/null || return 0
|
|
89
|
+
return 0
|
|
90
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: Stop
|
|
3
|
+
# Гард происшествия: ход, в котором исполнитель признал промах, не заканчивается, пока записи о
|
|
4
|
+
# происшествии нет. Stop.
|
|
5
|
+
#
|
|
6
|
+
# Зачем именно так. Происшествие — заход, в котором исполнитель сделал не то, а слой правил
|
|
7
|
+
# этого не отбил, — исправляемого кода за собой не оставляет. Такой заход кончается извинением
|
|
8
|
+
# в переписке: назавтра механизм промаха пересказывается уже приглаженно, остаются выводы, а из
|
|
9
|
+
# выводов правило не выводится. Разбор случался только тогда, когда владелец требовал его вслух.
|
|
10
|
+
#
|
|
11
|
+
# Ловится признание образцами, а не пониманием смысла: оценку «это был промах» назначал бы тот,
|
|
12
|
+
# кому она мешает, и порог плыл бы. Набор образцов виден, пополняется правкой и промахивается
|
|
13
|
+
# заметно — заход, признавший промах словами вне набора, гард пропускает, и это сказано вслух в
|
|
14
|
+
# договорённости, а не считается закрытым.
|
|
15
|
+
#
|
|
16
|
+
# Ловится на завершении хода, а не на отправке реплики: к моменту признания промах уже случился,
|
|
17
|
+
# и ловить раньше нечего. Этим он отличается от гарда разговора, у которого есть свой инструмент
|
|
18
|
+
# — вопрос владельцу.
|
|
19
|
+
#
|
|
20
|
+
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, отсутствии записи хода и повторном заходе ход
|
|
21
|
+
# РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
22
|
+
|
|
23
|
+
input="$(cat 2>/dev/null)"
|
|
24
|
+
[ -z "$input" ] && exit 0
|
|
25
|
+
|
|
26
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
27
|
+
|
|
28
|
+
# Повторный заход по тому же ходу не судится: гард сказал своё один раз и отпускает.
|
|
29
|
+
active="$(printf '%s' "$input" | jq -r '.stop_hook_active // false' 2>/dev/null)"
|
|
30
|
+
[ "$active" = "true" ] && exit 0
|
|
31
|
+
|
|
32
|
+
transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)"
|
|
33
|
+
[ -z "$transcript" ] && exit 0
|
|
34
|
+
[ -f "$transcript" ] || exit 0
|
|
35
|
+
|
|
36
|
+
root="${CLAUDE_PROJECT_DIR:-.}"
|
|
37
|
+
|
|
38
|
+
# Каталог записей у дерева свой. Заданный пустым — отказ дерева от требования: дереву, которое
|
|
39
|
+
# записей не ведёт, гард не навязывается.
|
|
40
|
+
notes_dir="${RT_POSTMORTEMS_DIR-docs/postmortems}"
|
|
41
|
+
[ -z "$notes_dir" ] && exit 0
|
|
42
|
+
[ -d "$root/$notes_dir" ] || exit 0
|
|
43
|
+
|
|
44
|
+
# Образцы признания промаха. Набор открыт и пополняется правкой: полнота его — открытый вопрос
|
|
45
|
+
# договорённости, а не обещание.
|
|
46
|
+
admitted_re='был неправ|был не прав|ошибс|моя ошибк|мой промах|промахнул|проглядел|не проверил|соврал|виноват|извин|прошу прощения|неверно утверждал|утверждение было ложн|принял на веру'
|
|
47
|
+
|
|
48
|
+
# Ход — это всё, что записано после последнего настоящего ввода владельца. Ответ инструмента
|
|
49
|
+
# приходит той же ролью, поэтому строки с `tool_result` вводом не считаются.
|
|
50
|
+
#
|
|
51
|
+
# Хвост в 400 строк: запись хода растёт всю сессию, а судится только последний ход.
|
|
52
|
+
verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r --arg re "$admitted_re" '
|
|
53
|
+
def is_input:
|
|
54
|
+
.type == "user"
|
|
55
|
+
and (((.message.content // []) | if type == "array"
|
|
56
|
+
then ([.[] | select(.type == "tool_result")] | length)
|
|
57
|
+
else 0 end) == 0);
|
|
58
|
+
|
|
59
|
+
(map(is_input) | rindex(true)) as $i
|
|
60
|
+
| (if $i == null then . else .[$i + 1:] end) as $turn
|
|
61
|
+
| [$turn[] | select(.type == "assistant") | (.message.content // [])[] | select(.type == "text") | .text] as $texts
|
|
62
|
+
| [$turn[] | select(.type == "assistant") | (.message.content // [])[] | select(.type == "tool_use")] as $uses
|
|
63
|
+
# Признак нечувствителен к регистру флагом, а не приведением: приведение знает только
|
|
64
|
+
# латиницу, и «Был неправ» с большой буквы проходило бы мимо набора образцов молча.
|
|
65
|
+
| (($texts | join("\n")) | test($re; "i")) as $admitted
|
|
66
|
+
| ($uses | map(
|
|
67
|
+
((.name // "") | test("^(Write|Edit|MultiEdit)$"))
|
|
68
|
+
and ((.input.file_path // "") | test("postmortem"))
|
|
69
|
+
) | any) as $wrote
|
|
70
|
+
| if $admitted and ($wrote | not) then "admit" else "pass" end
|
|
71
|
+
' 2>/dev/null)"
|
|
72
|
+
|
|
73
|
+
[ "$verdict" = "admit" ] || exit 0
|
|
74
|
+
|
|
75
|
+
# Запись, сделанная за эту сессию, снимает требование и без правки в этом же ходе: разбор мог
|
|
76
|
+
# лечь файлом ходом раньше — тем, в котором промах и признали.
|
|
77
|
+
if [ -n "$(find "$root/$notes_dir" -name '*.md' -newermt '-1 day' 2>/dev/null | head -1)" ]; then
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
reason="BLOCKED by postmortem-guard: в ответе признан промах, а записи о происшествии в \`$notes_dir/\` за сегодня нет. Происшествие — заход, в котором исполнитель сделал не то, а слой правил этого не отбил, — записывается в тот же заход: назавтра механизм промаха пересказывается уже приглаженно, и правило из него не выводится.
|
|
82
|
+
|
|
83
|
+
Запись называет: механизм промаха по шагам, что было доступно до него, чем ловилось и что из этого ушло в слой правил. Без последней строки это жалоба, а не разбор.
|
|
84
|
+
|
|
85
|
+
$notes_dir/<год>-<месяц>-<день>-<короткое имя>.md
|
|
86
|
+
|
|
87
|
+
Гард судит один ход: следующий заход не отбивается."
|
|
88
|
+
|
|
89
|
+
jq -n --arg r "$reason" '{decision:"block",reason:$r}' 2>/dev/null \
|
|
90
|
+
|| printf '{"decision":"block","reason":"postmortem-guard: признан промах — запиши разбор происшествия."}\n'
|
|
91
|
+
|
|
92
|
+
exit 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Нехватка функции профиля, сказанная вслух. НЕ гард: объявления `rt-hook:` у него нет, к
|
|
3
|
+
# событиям агента он не подключается. Его источают сами гарды — тем же приёмом, каким гейт
|
|
4
|
+
# источает карту, а гарды — запись наблюдений.
|
|
5
|
+
#
|
|
6
|
+
# Зачем он есть. Девять хуков пакета зовут функции профиля дерева, и у пяти проверка стоит до
|
|
7
|
+
# всякого поведения: нет функции — выход с нулём, не сделав ничего. Такой гард хуже
|
|
8
|
+
# отсутствующего: он лежит в дереве, стоит в настройке, виден в списке хуков и читается как
|
|
9
|
+
# работающий. Тишина при этом означает разом три разных вещи — «нечего проверять», «проверять
|
|
10
|
+
# нечем» и «всё в порядке», — и отличить их нечем.
|
|
11
|
+
#
|
|
12
|
+
# ЧТО ГОВОРИТСЯ. Имя функции и файл, в котором её определяют. Один раз за сессию: на каждый
|
|
13
|
+
# вызов та же строка повторялась бы десятки раз за заход и перестала бы читаться.
|
|
14
|
+
#
|
|
15
|
+
# ДЕЙСТВИЕ ВСЁ РАВНО ПРОПУСКАЕТСЯ. Хук сообщает о своей неполноте, а не судит правку: судить её
|
|
16
|
+
# нечем, и отбивать работу из-за ненастроенного дерева он не вправе.
|
|
17
|
+
|
|
18
|
+
# Куда кладётся отметка «об этом уже сказано». Каталог временных файлов, а не дерево: отметка
|
|
19
|
+
# живёт один заход и в историю не едет.
|
|
20
|
+
rt_needs_mark_dir() {
|
|
21
|
+
printf '%s' "${TMPDIR:-/tmp}"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Есть ли функция профиля. Успех — есть, и хук работает дальше. Отказ — нет, и об этом сказано.
|
|
25
|
+
#
|
|
26
|
+
# rt_needs rt_is_app_code task-flow-guard "$sid"
|
|
27
|
+
#
|
|
28
|
+
# Третий параметр — признак сессии, если хук его знает. Не знает — отметка кладётся на день:
|
|
29
|
+
# без признака «один раз за сессию» превратилось бы в «один раз за всю жизнь машины».
|
|
30
|
+
rt_needs() {
|
|
31
|
+
command -v "$1" >/dev/null 2>&1 && return 0
|
|
32
|
+
|
|
33
|
+
rt_needs_key="${3:-$(date +%Y%m%d 2>/dev/null || printf 'nosession')}"
|
|
34
|
+
rt_needs_mark="$(rt_needs_mark_dir)/rt-kit-needs-$1-$rt_needs_key"
|
|
35
|
+
if [ ! -f "$rt_needs_mark" ]; then
|
|
36
|
+
printf '%s: нет функции %s — её определяют в .claude/rt-kit/project.sh, а умолчание везёт пакет в .claude/rt-kit/defaults/project.sh\n' \
|
|
37
|
+
"${2:-хук}" "$1" >&2
|
|
38
|
+
printf 'проверка не работает, действие пропущено\n' >&2
|
|
39
|
+
: >"$rt_needs_mark" 2>/dev/null || true
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
return 1
|
|
43
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# rt-hook: PreToolUse Edit|Write|MultiEdit|mcp__webstorm__create_new_file
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
3
4
|
# Гард якоря для спек. PreToolUse на правке разметки.
|
|
4
5
|
#
|
|
5
6
|
# Спеки адресуют элементы только через этот атрибут. Классы оформления меняются вместе с
|
|
@@ -56,10 +57,16 @@ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../d
|
|
|
56
57
|
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
57
58
|
done
|
|
58
59
|
|
|
60
|
+
# Слово о нехватке функции профиля: хук, вышедший молча, неотличим от работающего. Файл может
|
|
61
|
+
# быть не разложен — тогда остаётся прежнее поведение, молчаливое.
|
|
62
|
+
# shellcheck disable=SC1090
|
|
63
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
64
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
65
|
+
|
|
59
66
|
# Разметка приложения живёт там же, где его код. Без этой положительной проверки гард
|
|
60
67
|
# распространялся на любой файл разметки на диске — черновик вне дерева отклонялся требованием
|
|
61
68
|
# проставить якоря.
|
|
62
|
-
if
|
|
69
|
+
if rt_needs rt_is_app_code qa-dataid-guard; then
|
|
63
70
|
rt_is_app_code "$path" || exit 0
|
|
64
71
|
fi
|
|
65
72
|
|
|
@@ -75,7 +82,7 @@ added="$(printf '%s' "$input" | jq -r '
|
|
|
75
82
|
' 2>/dev/null)"
|
|
76
83
|
[ -z "$added" ] && exit 0
|
|
77
84
|
|
|
78
|
-
decorative="$(
|
|
85
|
+
decorative="$(rt_needs rt_qa_decorative qa-dataid-guard && rt_qa_decorative 2>/dev/null)"
|
|
79
86
|
component_re="${RT_QA_COMPONENT_RE:--}"
|
|
80
87
|
|
|
81
88
|
# Открывающие теги разбираются ЦЕЛИКОМ: тег занимает несколько строк, и якорь часто стоит не в
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# rt-hook: PreToolUse Edit|Write|MultiEdit|mcp__webstorm__create_new_file
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
3
4
|
# Гард «ничего не пишется с нуля». PreToolUse на правке кода и разметки.
|
|
4
5
|
#
|
|
5
6
|
# Линтеры знают правила, но не знают ИНВЕНТАРЬ: линтер стилей поймает сырой цвет, линтер кода —
|
|
@@ -61,11 +62,17 @@ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../d
|
|
|
61
62
|
# shellcheck disable=SC1090
|
|
62
63
|
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
63
64
|
done
|
|
64
|
-
|
|
65
|
+
|
|
66
|
+
# Слово о нехватке функции профиля: хук, вышедший молча, неотличим от работающего. Файл может
|
|
67
|
+
# быть не разложен — тогда остаётся прежнее поведение, молчаливое.
|
|
68
|
+
# shellcheck disable=SC1090
|
|
69
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
70
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
71
|
+
rt_needs rt_reinvented_in reuse-first-guard || exit 0
|
|
65
72
|
|
|
66
73
|
# Правила этого дерева действуют на код этого дерева: без положительной проверки гард требовал
|
|
67
74
|
# бы собирать готовым и в черновике за пределами дерева.
|
|
68
|
-
if
|
|
75
|
+
if rt_needs rt_is_app_code reuse-first-guard; then
|
|
69
76
|
rt_is_app_code "$path" || exit 0
|
|
70
77
|
fi
|
|
71
78
|
|
|
@@ -38,6 +38,7 @@ command -v skill_for >/dev/null 2>&1 || exit 0
|
|
|
38
38
|
|
|
39
39
|
req=""
|
|
40
40
|
target=""
|
|
41
|
+
kind=""
|
|
41
42
|
case "$tool" in
|
|
42
43
|
# Инструмент среды заводит файл теми же двумя данными, только называет их иначе — без этой
|
|
43
44
|
# ветки файл заводился мимо гейта.
|
|
@@ -61,6 +62,12 @@ case "$tool" in
|
|
|
61
62
|
# приходит в обычный сервис, а число-настройка в обычный класс.
|
|
62
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)"
|
|
63
64
|
req="$(skill_for edit "$target" "$written" 2>/dev/null)"
|
|
65
|
+
# Род правки для наблюдения. Одно расширение, без пути и без имени файла: наблюдение
|
|
66
|
+
# уезжает наружу, и всё, кроме рода, там было бы адресом этого дерева.
|
|
67
|
+
case "${target##*/}" in
|
|
68
|
+
*.*) kind="${target##*.}" ;;
|
|
69
|
+
*) kind="none" ;;
|
|
70
|
+
esac
|
|
64
71
|
;;
|
|
65
72
|
# Терминал среды исполняет ту же командную строку и кладёт её в то же поле: без этой ветки
|
|
66
73
|
# коммит из него не требовал правила, тогда как тот же коммит из оболочки требовал.
|
|
@@ -77,9 +84,11 @@ case "$tool" in
|
|
|
77
84
|
[ -n "$inner" ] && target="$inner"
|
|
78
85
|
fi
|
|
79
86
|
req="$(skill_for bash "$target" "" 2>/dev/null)"
|
|
87
|
+
kind="command"
|
|
80
88
|
;;
|
|
81
89
|
mcp__claude-in-chrome__*)
|
|
82
90
|
req="$(skill_for browser "$tool" "" 2>/dev/null)"
|
|
91
|
+
kind="browser"
|
|
83
92
|
;;
|
|
84
93
|
*) exit 0 ;;
|
|
85
94
|
esac
|
|
@@ -108,6 +117,12 @@ done
|
|
|
108
117
|
[ -z "$want" ] && exit 0
|
|
109
118
|
req="$want"
|
|
110
119
|
|
|
120
|
+
# Отбитие — наблюдение: правило, которое приходится требовать чаще прочего, и род правки, на
|
|
121
|
+
# котором это происходит, говорят о слое правил больше, чем список загруженного.
|
|
122
|
+
# shellcheck disable=SC1090
|
|
123
|
+
[ -f "$rt_hooks_dir/observe.sh" ] && . "$rt_hooks_dir/observe.sh" 2>/dev/null
|
|
124
|
+
command -v rt_note >/dev/null 2>&1 && rt_note gate-deny "res=$req" "kind=$kind" "sid=$sid"
|
|
125
|
+
|
|
111
126
|
reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill и повтори действие. Для этой области это происходит один раз за сессию."
|
|
112
127
|
|
|
113
128
|
# Правило называет свой закон одним словом, а слоёв законов два: общий лежит в корне, закон
|
|
@@ -18,4 +18,11 @@ dir="${TMPDIR:-/tmp}/claude-skill-gate"
|
|
|
18
18
|
mkdir -p "$dir" 2>/dev/null || exit 0
|
|
19
19
|
printf '%s\n' "$skill" >> "$dir/${sid}.loaded" 2>/dev/null
|
|
20
20
|
|
|
21
|
+
# Та же загрузка вторым адресом — в наблюдения дерева. Запись выше живёт до сжатия контекста и
|
|
22
|
+
# гибнет вместе с ним: она отвечает гейту на вопрос «загружено ли», и больше ни на что.
|
|
23
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
# shellcheck disable=SC1090
|
|
25
|
+
[ -f "$rt_hooks_dir/observe.sh" ] && . "$rt_hooks_dir/observe.sh" 2>/dev/null
|
|
26
|
+
command -v rt_note >/dev/null 2>&1 && rt_note skill-load "res=$skill" "sid=$sid"
|
|
27
|
+
|
|
21
28
|
exit 0
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# rt-hook: SessionStart startup|resume|compact|clear
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
3
4
|
# SessionStart: состояние незаконченной работы уезжает в контекст на каждом запуске сессии.
|
|
4
5
|
#
|
|
5
6
|
# Памятью это не держится по той же причине, что и словарь: замысел читают перед правкой
|
|
@@ -28,6 +29,12 @@ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../d
|
|
|
28
29
|
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
29
30
|
done
|
|
30
31
|
|
|
32
|
+
# Слово о нехватке функции профиля: хук, вышедший молча, неотличим от работающего. Файл может
|
|
33
|
+
# быть не разложен — тогда остаётся прежнее поведение, молчаливое.
|
|
34
|
+
# shellcheck disable=SC1090
|
|
35
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
36
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
37
|
+
|
|
31
38
|
TASKS_DIR="${RT_TASKS_DIR:-docs/tasks}"
|
|
32
39
|
[ -z "$TASKS_DIR" ] && exit 0
|
|
33
40
|
|
|
@@ -43,13 +50,20 @@ emit() {
|
|
|
43
50
|
# Ветка под задачу без папки — работа идёт мимо. Сессию не рвём: SessionStart, отбивающий
|
|
44
51
|
# запуск, оставляет владельца без агента вовсе, а правку кода поймает `task-flow-guard`.
|
|
45
52
|
if [ ! -d "$DIR" ]; then
|
|
46
|
-
if
|
|
53
|
+
if rt_needs rt_task_branch_ok task-context-load && rt_task_branch_ok "$branch"; then
|
|
47
54
|
{
|
|
48
55
|
printf 'РАБОТА БЕЗ ПАПКИ ЗАДАЧИ.\n\n'
|
|
49
56
|
printf 'Ветка `%s` названа задачей, а `%s/` нет: ход работы записывать некуда,\n' "$branch" "$DIR"
|
|
50
57
|
printf 'и следующий заход начнёт с расспросов владельца.\n\n'
|
|
51
58
|
printf 'Собрать с образца:\n\n cp -r %s/_template %s\n\n' "$TASKS_DIR" "$DIR"
|
|
52
|
-
|
|
59
|
+
# О соседнем ресурсе — условно и по имени: пакет не знает, разложен ли он здесь,
|
|
60
|
+
# а сказанное безусловно приходит в контекст каждой сессии и врёт про дерево тем
|
|
61
|
+
# увереннее, что печатает это сам инструмент.
|
|
62
|
+
if [ -f "$rt_hooks_dir/task-flow-guard.sh" ]; then
|
|
63
|
+
printf 'Правку кода приложения до этого отбивает гард `task-flow-guard`. Правило — скил `task-flow`.\n'
|
|
64
|
+
else
|
|
65
|
+
printf 'Правило — скил `task-flow`. Гарда `task-flow-guard` в дереве нет: правку кода до этого не отбивает ничто.\n'
|
|
66
|
+
fi
|
|
53
67
|
} | emit
|
|
54
68
|
fi
|
|
55
69
|
exit 0
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# rt-hook: PreToolUse Edit|Write|MultiEdit
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
3
4
|
# PreToolUse guard for Edit|Write|MultiEdit: код не пишется раньше замысла.
|
|
4
5
|
#
|
|
5
6
|
# Работа идёт много заходов, и между ними исполнитель не помнит ничего. Замысел, лежащий на
|
|
@@ -45,11 +46,17 @@ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../d
|
|
|
45
46
|
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
46
47
|
done
|
|
47
48
|
|
|
49
|
+
# Слово о нехватке функции профиля: хук, вышедший молча, неотличим от работающего. Файл может
|
|
50
|
+
# быть не разложен — тогда остаётся прежнее поведение, молчаливое.
|
|
51
|
+
# shellcheck disable=SC1090
|
|
52
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
53
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
54
|
+
|
|
48
55
|
# Признак «правка меняет поведение» — путь, а не оценка на глаз: оценку назначает тот, кому
|
|
49
56
|
# она мешает, и порог плывёт. Где живёт код приложения, знает профиль: правила, тексты, обвязка
|
|
50
57
|
# и зависимости под требование не попадают — иначе разбор задачи нельзя было бы вести до
|
|
51
58
|
# заведения ветки.
|
|
52
|
-
|
|
59
|
+
rt_needs rt_is_app_code task-flow-guard || exit 0
|
|
53
60
|
rt_is_app_code "$path" || exit 0
|
|
54
61
|
|
|
55
62
|
# Каталог папок задач: у дерева он свой, но имя обычно общее.
|
|
@@ -70,7 +77,7 @@ git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
|
70
77
|
branch="$(git branch --show-current 2>/dev/null)"
|
|
71
78
|
[ -z "$branch" ] && exit 0 # detached HEAD — не про наш случай
|
|
72
79
|
|
|
73
|
-
if
|
|
80
|
+
if rt_needs rt_task_branch_ok task-flow-guard && ! rt_task_branch_ok "$branch"; then
|
|
74
81
|
deny "BLOCKED by task-flow: правка кода идёт в ветке под задачу, а текущая ветка — '${branch}'. Заведи задачу (npm run task:new -- --title '…' --slug <slug>) и ветку под её номером, затем повтори. Правило — скил task-flow."
|
|
75
82
|
fi
|
|
76
83
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# rt-hook: PostToolUse .*
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
3
4
|
# rt-hook: PreToolUse .*
|
|
4
5
|
# Заполнение окна: заход доводится до логической точки заранее, а не обрывается на середине.
|
|
5
6
|
#
|
|
@@ -34,6 +35,12 @@ for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../d
|
|
|
34
35
|
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
35
36
|
done
|
|
36
37
|
|
|
38
|
+
# Слово о нехватке функции профиля: хук, вышедший молча, неотличим от работающего. Файл может
|
|
39
|
+
# быть не разложен — тогда остаётся прежнее поведение, молчаливое.
|
|
40
|
+
# shellcheck disable=SC1090
|
|
41
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
42
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
43
|
+
|
|
37
44
|
window="${RT_WINDOW_TOKENS:-}"
|
|
38
45
|
case "$window" in
|
|
39
46
|
'' | *[!0-9]*) exit 0 ;;
|
|
@@ -126,7 +133,7 @@ case "$tool" in
|
|
|
126
133
|
Bash | mcp__webstorm__execute_terminal_command)
|
|
127
134
|
# Поставка и сверки: коммит, пуш, отчёт, колонка задачи, состояние дерева. Список
|
|
128
135
|
# дописывается профилем дерева — клиент хостинга и имена команд у каждого свои.
|
|
129
|
-
if
|
|
136
|
+
if rt_needs rt_handoff_allowed_cmd window-fill-guard && rt_handoff_allowed_cmd "$cmd"; then
|
|
130
137
|
allowed=1
|
|
131
138
|
fi
|
|
132
139
|
;;
|
|
@@ -47,3 +47,8 @@
|
|
|
47
47
|
видит, проверки текстов на них не смотрят, и отказ выглядит сделанным ровно до того, как
|
|
48
48
|
читатель наткнётся на снятое слово в заголовке. Читатель при этом заключает, что от слова
|
|
49
49
|
не отказывались вовсе.
|
|
50
|
+
- **Текст, который переносится в чужое дерево, не описывает состояние этого дерева как факт.**
|
|
51
|
+
О соседней части он говорит условно и называет её по имени: что в дереве стоит, а чего нет,
|
|
52
|
+
знает само дерево, а не текст, приехавший в него. Утверждение, сказанное безусловно, врёт тем
|
|
53
|
+
увереннее, что печатает его сам инструмент, — и поправить его дерево не может, если правки на
|
|
54
|
+
месте у такого текста не предусмотрено.
|
|
@@ -47,3 +47,12 @@
|
|
|
47
47
|
выключают в настройке инструмента, а не обходят в каждом месте.** Обход приходится повторять
|
|
48
48
|
столько раз, сколько таких мест, и ни в одном из них не написано, зачем он: со стороны это
|
|
49
49
|
выглядит ошибкой автора, а не решением.
|
|
50
|
+
- **Польза правила подтверждается наблюдением за тем, как им пользуются, а не мнением о нём.**
|
|
51
|
+
Правило, которого не открыли ни разу, и правило, на котором держится половина работы, в тексте
|
|
52
|
+
выглядят одинаково — и правится первым обычно то, о чём вспомнили, а не то, что мешает.
|
|
53
|
+
Наблюдение ведётся там же, где идёт работа, и переживает отдельный заход: запись, которая
|
|
54
|
+
умирает вместе с сессией, отвечает только на вопрос «что было минуту назад».
|
|
55
|
+
- **Наблюдение за работой не выносит наружу ничего, кроме того, что общее у всех.** Имя правила,
|
|
56
|
+
род события и версия одинаковы везде, где стоит слой правил; путь, домен и имя дерева
|
|
57
|
+
принадлежат одному дереву и в чужом месте не значат ничего, кроме утечки. Держится это
|
|
58
|
+
проверкой на выносящей стороне, а не памятью того, кто пишет.
|
|
@@ -13,8 +13,24 @@
|
|
|
13
13
|
- **Пробел закрывается вопросом владельцу, а не догадкой.** Догадка неотличима от знания:
|
|
14
14
|
она попадает в работу молча и обнаруживается только при приёмке, когда переделывать дороже
|
|
15
15
|
всего.
|
|
16
|
+
- **Вопрос, у которого есть очевидный ответ, работу не останавливает.** Исполнитель называет
|
|
17
|
+
допущение, идёт дальше и записывает его туда же, где идёт работа. Останавливает только тот
|
|
18
|
+
пробел, при котором любая догадка делает работу опасной или бесполезной. Вопрос, заданный
|
|
19
|
+
вместо работы, выглядит добросовестно, а стоит владельцу захода.
|
|
20
|
+
- **Остановка называется первой строкой.** Сообщение, которым исполнитель останавливается,
|
|
21
|
+
начинается с того, чего он ждёт и что будет, если ответа не будет. Замеры, находки и разбор
|
|
22
|
+
к этому моменту уже записаны в ход работы — в сообщении владельцу они лишние. Чем подробнее
|
|
23
|
+
отчёт, тем надёжнее вопрос в нём тонет, и владелец переспрашивает, почему работа стоит.
|
|
16
24
|
- **Владельцу не задаётся вопрос, ответ на который уже записан.** Записанное читают до
|
|
17
25
|
разговора, а не вместо ответа: вопрос о том, что уже решено, обесценивает и остальные.
|
|
26
|
+
- **Вопрос владельцу задаётся после того, как ответ искали в дереве.** Что лежит в дереве,
|
|
27
|
+
исполнитель узнаёт сам: имя, путь, наличие файла и устройство репозитория он берёт командой,
|
|
28
|
+
а не у владельца. Вопрос, ответ на который дала бы одна команда, стоит владельцу захода и
|
|
29
|
+
обесценивает заданные рядом.
|
|
30
|
+
- **Утверждение о дереве стоит ровно столько, сколько команда, его показавшая.** Отрицание —
|
|
31
|
+
«здесь нет», «этого не заводили», «такого файла не бывает» — произносится только как вывод
|
|
32
|
+
команды. Не проверенное отрицание опаснее вопроса: вопрос владелец поправит, а факт от
|
|
33
|
+
исполнителя примет на веру, потому что тот в дерево смотрит.
|
|
18
34
|
- **Решение, однажды записанное, действует, пока его не отменили, и читается до того, как
|
|
19
35
|
принимается заново.** Отменённое решение следа в работе не оставляет — по результату не
|
|
20
36
|
видно ни того, что его принимали, ни того, что от него отказались. Принятое заново оно
|
|
@@ -49,6 +65,11 @@
|
|
|
49
65
|
читается как случайное и отменяется следующим заходом, а отменённое возвращается третьим.
|
|
50
66
|
- **Граница работы названа до её начала.** Не названная вслух граница не существует: правка
|
|
51
67
|
расползается на соседнее, и снимать её приходится вручную.
|
|
68
|
+
- **Действия, которые исполнитель не делает сам, названы списком.** Всё, что уходит за
|
|
69
|
+
пределы рабочего дерева или не откатывается — запись в общий репозиторий, публикация, отчёт,
|
|
70
|
+
правка общего документа, — делается по слову владельца, и слово это даётся на действие, а не
|
|
71
|
+
на работу целиком. Не названная списком граница выводится из общих слов: «делай, что нужно
|
|
72
|
+
по плану» прочитывается как разрешение на всё, что в плане подразумевалось.
|
|
52
73
|
- **Признак закрытия работы назван до её начала и проверяем.** «Работает» признаком не
|
|
53
74
|
является: под ним каждый заход понимает своё, и работа закрывается тогда, когда надоела.
|
|
54
75
|
- **Начатая и брошенная работа видна.** Брошенное на середине выглядит так же, как
|
|
@@ -65,3 +86,21 @@
|
|
|
65
86
|
- **Незаданный вопрос замечает только тот, кто знает, чего хотел.** Вопрос, которого не
|
|
66
87
|
задали, следа не оставляет: работа выглядит понятой ровно до приёмки, и вывести отсутствие
|
|
67
88
|
вопроса не из чего.
|
|
89
|
+
- **Происшествие названо признаком, а не оценкой заднего числа.** Происшествие — заход, в
|
|
90
|
+
котором исполнитель сделал не то, а слой правил этого не отбил. Дефект в коде происшествием
|
|
91
|
+
не является: его объясняет договорённость о продукте. Признак записан один раз, а не
|
|
92
|
+
выводится каждым заходом заново — иначе его назначает тот, кому он мешает.
|
|
93
|
+
- **Происшествие кончается записью, и запись делается в тот же заход.** Через день механизм
|
|
94
|
+
промаха пересказывается уже приглаженно: остаются выводы, а из выводов правило не выводится.
|
|
95
|
+
Запись называет механизм промаха по шагам, что было доступно до него, чем ловилось и что из
|
|
96
|
+
этого ушло в слой правил.
|
|
97
|
+
- **Запись без правки слоя правил закрытой не считается.** Разбор, из которого не вышло ни
|
|
98
|
+
предложения, ни правки закона, правила или паттерна, — жалоба: он объясняет случившееся и
|
|
99
|
+
ничего не меняет, а значит повторится.
|
|
100
|
+
- **Закрытая работа оставляет то, что узнала о правилах, там, откуда это возьмёт машина.**
|
|
101
|
+
Понимание, добытое одной работой, всего дороже соседней — и живёт оно ровно до конца захода,
|
|
102
|
+
если осталось в разговоре. Записанное свободным пересказом лежит не хуже, но переносить его
|
|
103
|
+
приходится руками, и переносится оно ровно до первой занятой недели.
|
|
104
|
+
- **У предложенной правки правил назван адрес: сам слой правил, имена этого дерева или его
|
|
105
|
+
надстройка.** Без адреса правку кладут туда, где она видна автору, — то есть в своё дерево, —
|
|
106
|
+
и общее оседает в одном месте, оставаясь неизвестным всем остальным.
|
|
@@ -212,26 +212,30 @@ npm run task:move -- 86 in-review
|
|
|
212
212
|
Конвейер видит только отправленное, а отправляется оно пушем. Линтеры, юниты и сценарии хуков
|
|
213
213
|
снимает гейт пуша — ниже то, чего он не знает.
|
|
214
214
|
|
|
215
|
-
1.
|
|
215
|
+
1. **Главная ветка влита в эту ветку** — `git fetch origin && git merge origin/main`.
|
|
216
|
+
Всё, что проверяется ниже, проверяется от этого основания: PR с разошедшейся ветки
|
|
217
|
+
показывает ревьюверу правку вперемешку с чужой. Порядок и разбор конфликта — паттерн
|
|
218
|
+
`git-workflow-merge`.
|
|
219
|
+
2. **В ветке только та правка, за которой её заводили** — `git diff main...HEAD --stat`. Чужой
|
|
216
220
|
домен в списке файлов означает, что правка расползлась, и её надо вернуть в свои границы.
|
|
217
|
-
|
|
221
|
+
3. **Ни мока, ни подменённого ответа, ни отладочной строки** — `git diff main...HEAD` читается
|
|
218
222
|
целиком, а не по именам файлов. На прод они уезжают молча и портят настоящие данные.
|
|
219
|
-
|
|
223
|
+
4. **Документ едет тем же коммитом.** Пару называет `docs-guard`, но спек домена и правку его
|
|
220
224
|
поведения он не знает — это остаётся за автором.
|
|
221
|
-
|
|
225
|
+
5. **Проверки текстов и раскладки зелёные** — те, что дерево завело в `tools/`. Какие именно
|
|
222
226
|
есть здесь — `implementation.md` правила.
|
|
223
|
-
|
|
224
|
-
|
|
227
|
+
6. **Все приложения дерева собираются** — `nx build` по каждому. Гейт пуша сборку не гоняет.
|
|
228
|
+
7. **Видимый текст заведён во всех локалях перевода** — тестом полноты словарей, если дерево
|
|
225
229
|
переводится.
|
|
226
|
-
|
|
230
|
+
8. **Правка вёрстки подтверждена замером**, а не взглядом, и снята при узком экране — паттерн
|
|
227
231
|
`browser-verification-measure`.
|
|
228
|
-
|
|
232
|
+
9. **Правка разметки публичного сайта проверена на прод-сборке по всем локалям перевода** —
|
|
229
233
|
паттерн `seo-verify`.
|
|
230
|
-
|
|
231
|
-
|
|
234
|
+
10. **PR привязан к рабочему элементу**, ревьювер и исполнитель стоят.
|
|
235
|
+
11. **Заголовок PR несёт номер элемента и называет работу сделанной:** `[<номер>] <Что
|
|
232
236
|
сделано>`, тем же номером, что стоит у элемента и в имени ветки.
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
12. **Очередь работ сходится** — `npm run check:board`.
|
|
238
|
+
13. **Состояние PR прочитано, а не выведено из кодов возврата.**
|
|
235
239
|
|
|
236
240
|
Сразу после публикации элемент переводится в разбор, и сверка очереди прогоняется ещё раз: до
|
|
237
241
|
открытия PR состояние она не судит, а после открытия расхождение видит.
|