Бесплатный интерактивный курс · aicoding.space

skills-devops: тридцать навыков для дежурного инженера

Практический курс по пакету @dzhechkov/skills-devops для того, кто впервые подключает навыки к своему AI-агенту. Вместе с Тимуром ты установишь пакет, поймёшь, как навык включается по фразе и где проходят его границы, разберёшь протоколы ревью, аудита безопасности, тестов и починки CI, проведёшь миграцию базы без простоя, увидишь, как гейт дашбордов перестал верить самоотчёту, разведёшь инцидент и проблему, задеплоишь репозиторий на ВМ Cloud.ru и узнаешь, что именно покрывает подпись пакета.

Содержание курса

1. Зачем агенту пакет навыков?

Что такое skills-devops одной фразой и откуда взялись тридцать навыков.

Ключевая мысль: пакет из 30 навыков для DevOps-задач

Тимур — дежурный инженер платформенной команды. Сети и облако он знает наизусть, а навыки для AI-агента подключает впервые. Спросил он ровно то, что сейчас думаешь ты: «зачем агенту отдельный пакет, если он и так всё умеет?»

Ответ короткий: @dzhechkov/skills-devops — это пакет из 30 навыков для DevOps-задач. Навык — это файл SKILL.md с пошаговой процедурой, разделами «когда использовать» и «когда НЕ использовать» и описанием формата результата. Агент без навыка отвечает по памяти; агент с навыком идёт по протоколу, который кто-то уже проверил на живых задачах.

Откуда взялись тридцать навыков:

  • 10 канонизированы из проекта gitlawb/openclaude-skills (лицензия MIT): pr-review, security-audit, test-writer, ci-fix, codeql-fix, database-review, debugging, frontend-implementation, git-conflict-resolve, provider-debug;
  • 20 написаны в самом хабе — от github-actions и kubernetes до incident-response, problem-management и deploy-on-cloudru-vm.

Пакет живёт на npm: страница @dzhechkov/skills-devops; исходники — в зеркале на GitHub. В package.json на момент написания курса стоит версия 0.3.17.

Компромисс: ты получаешь проверенные протоколы вместо импровизации, но платишь контекстом агента — навыки многословны. Измерено: observability/SKILL.md — 818 строк, pr-review/SKILL.md — 80. Агент загружает навык целиком, когда тот срабатывает.

💬 Просто попроси. Команды в этом курсе нужны, чтобы ты понимал, что происходит под капотом. В Claude Code достаточно сказать «проверь этот PR» — и навык pr-review включится сам. Тимур за первую неделю ни разу не набрал имя навыка руками.

2. Установка: пресет, точечный выбор, npm

Три команды из README и чем они отличаются.

Ключевая мысль: команда dz init --preset devops

Хватит вступлений — Тимур уже открыл терминал, открывай и ты.

README пакета даёт три способа установки, и это не три синонима, а три разных решения:

  1. Пресет целиком. dz init --target claude-code --preset devops — все тридцать навыков за один вызов. Тимур начал именно так.
  2. Точечный выбор. dz init --target claude-code --select pr-review,security-audit,test-writer — только названные навыки, через запятую.
  3. Пакет напрямую. npm install @dzhechkov/skills-devops — как обычная зависимость, без раскладки под платформу.

Грабли Тимура — не повторяй. Он поставил пресет целиком в проект, где нужны были только ревью и тесты, и агент стал предлагать kubernetes на каждый вопрос про контейнеры. Пресет — быстрый старт; точечный выбор — чистый проект.

Флаг --target — это платформа, под которую dz раскладывает файлы навыков. В README примеры даны для claude-code; сам dz умеет и другие цели, но это уже курс про harness-cli, а не про этот пакет.

Компромисс: пресет ставится за минуту, но тащит лишнее; точечный выбор чист, но требует знать имена навыков (их ты найдёшь в следующей секции); npm-установка даёт версию и README, но не раскладывает файлы под агента.

💬 Просто попроси. «Поставь DevOps-навыки в этот проект» → ассистент выполнит dz init --target claude-code --preset devops; «добавь только ревью PR» → --select pr-review.

3. Навык включается по фразе

Автоактивация: фраза задачи совпадает с триггерами из SKILL.md.

Ключевая мысль: триггерные фразы навыка

Пакет стоит. Тимур пишет агенту «посмотри PR #42» — и вдруг видит в ответе структурированное ревью с вердиктом и цитатами file:line. Он ничего не включал. Что произошло?

Сработала автоактивация: навыки включаются сами, когда твоя задача совпадает с их триггерными фразами. Триггеры описаны в шапке каждого SKILL.md — в поле description и в разделе «When to use». README приводит три примера:

  • «Review this PR» → pr-review;
  • «Set up Terraform modules for AWS» → terraform;
  • «Fix the failing CI pipeline» → ci-fix.

Три взгляда на одно и то же, чтобы уложилось:

  1. Общая картина. Ты называешь намерение, а не имя навыка. Имена в пакете можно вообще не помнить.
  2. По шагам. Агент читает фразу → сверяет с триггерами → загружает SKILL.md → идёт по его процедуре → отвечает в формате из раздела «Output Format».
  3. Конкретный артефакт. Триггеры навыка deploy-on-cloudru-vm в его шапке — «задеплой в cloud.ru», «deploy this repo to a VM», «дай ссылку на подключение». Русские фразы там прописаны явно.

Две команды, чтобы смотреть в каталог руками: dz info <skill-id> показывает точные триггеры и файлы навыка, dz registry search <слово> ищет навык по слову.

Компромисс: автоактивация избавляет от заучивания имён, но зависит от формулировки — фраза мимо триггеров оставит агента без навыка, и он ответит по памяти, не сказав об этом. Тимур теперь формулирует задачу словами из области: «ревью», «инцидент», «миграция».

4. Границы навыка: «когда НЕ использовать»

Каждый навык знает соседей и передаёт задачу дальше — реши за Тимура, кому.

Ключевая мысль: границы навыка: когда не использовать

У каждого навыка в пакете есть раздел «When NOT to use» — и это не отписка, а карта передач. Навык знает своих соседей и говорит, кому отдать задачу, если она не его.

Тимур сначала не поверил, что это важно. Потом попросил pr-review «найти дыры в безопасности» — и получил обычное ревью с одной строчкой про секреты. Открыл SKILL.md — а там прямо написано: «security-focused review only → use security-audit».

Несколько границ из самих файлов навыков:

  • pr-review: не для создания PR, не для починки CI (→ ci-fix), не для чисто security-ревью (→ security-audit);
  • security-audit: не для общего ревью (→ pr-review), не для одной конкретной SAST-находки (→ codeql-fix);
  • debugging: не для ошибок сборки и компиляции (→ ci-fix), не для проектирования мониторинга (→ observability);
  • observability: не для живого инцидента (→ incident-response), не для отладки конкретного бага (→ debugging);
  • problem-management: «система лежит ПРЯМО СЕЙЧАС → incident-response»; сначала восстановить, потом искать причину.

Теперь ты в роли Тимура: в упражнении три ситуации, и в каждой надо выбрать навык. Единственно верного ответа нет только в одном месте — где задача сидит на границе двух навыков; там важно объяснить, почему ты отдал её именно так.

Компромисс: границы навыка делают ответ предсказуемым, но требуют один раз прочитать разделы «When NOT to use» — иначе ты будешь спрашивать у ревьюера то, что умеет аудитор.

5. pr-review: находки по серьёзности

Десять шагов протокола ревью и три уровня: Blocker, Important, Nit.

Ключевая мысль: группировка находок по серьёзности

Первый навык, который Тимур прочитал целиком, — pr-review. Всего 80 строк, а порядок в голове наводит на неделю вперёд.

Протокол — десять шагов, и порядок в нём не случаен:

  1. Получить diff (gh pr diff <number> или git diff <base>...<head>).
  2. Понять объём: сколько файлов, сколько строк, какие области.
  3. Прочитать изменённый код в контексте — 30–50 строк вокруг каждого изменения; diff в отрыве от файла не ревьюят.
  4. Проверить каждое изменение по восьми измерениям: корректность, обработка ошибок, крайние случаи, имена, тесты, безопасность, производительность, ломающие изменения.
  5. Сгруппировать находки по серьёзности — это сердце протокола.
  6. Написать ревью: точный file:line, цитата кода, что не так и почему, конкретное исправление.
  7. Резюме PR в 2–3 предложения.
  8. Вердикт: Approve / Request changes / Comment.
  9. Проверка полноты: миграция, документация, changelog — всё, что описание обещает, а diff не доставляет.
  10. Большой PR (>600 строк или 20+ файлов) — сказать, что его надо разбить, и предложить как.

Три уровня серьёзности:

  • Blocker — чинить до слияния: баги, потеря данных, дыры безопасности, сломанные тесты;
  • Important — стоит починить до слияния: пропущенная обработка ошибок, путаные имена, нет тестов на новое поведение;
  • Nit — приятно, но не блокирует: стиль, мелкая читаемость, опечатки.

Правило, которое Тимур переписал себе на стикер: каждый комментарий обязан быть действенным. «Это можно сделать лучше» — не комментарий. «Переименуй x в userCount, потому что на строке 47 это счётчик» — комментарий.

Компромисс: группировка находок по серьёзности заставляет ревьюера решать, что реально блокирует, — это дольше, чем вывалить список; зато автор PR видит, с чего начинать, и не тонет в Nit.

6. security-audit: находка без пути эксплуатации — не находка

Восемь категорий, четыре уровня серьёзности и одно жёсткое правило.

Ключевая мысль: путь эксплуатации для каждой находки

Вопрос без лёгкого ответа, с которого Тимур начал читать security-audit: чем аудит безопасности отличается от списка страхов?

Навык отвечает одним правилом: у каждой находки должен быть путь эксплуатации. Не «здесь теоретически может быть уязвимость», а четыре конкретных поля:

  • Input trigger — какой именно ввод пошлёт атакующий;
  • Path — через какие функции он пройдёт от точки входа до опасного стока;
  • Impact — что атакующий получит: данные, привилегии, выполнение кода, отказ в обслуживании;
  • Fix — конкретное изменение кода.

Пример из самого навыка: «отправка name='; DROP TABLE users; -- в /api/users выполнит произвольный SQL, потому что значение подставляется в запрос на строке 42» — это находка. «Стоит подумать о санитизации» — нет.

Порядок работы — семь шагов: сначала границы доверия (откуда приходят чужие данные), потом обход восьми категорий — инъекции, аутентификация и авторизация, секреты, файловые операции, сетевые операции, десериализация, XXE/SSRF, зависимости. Дальше — документирование каждой находки по четырём полям, серьёзность, проверка защит фреймворка (шаблонизатор уже экранирует? CSRF-middleware есть?) и честное признание существующих защит.

Четыре уровня серьёзности: Critical — удалённое выполнение кода, обход аутентификации; High — SQL-инъекция, хранимый XSS, повышение привилегий; Medium — CSRF, открытый редирект, утечка версий; Low — отсутствующие заголовки, болтливые ошибки.

И ещё одно правило, которое Тимур не ожидал увидеть: если уязвимостей нет — сказать об этом прямо. Выдумывать находки, чтобы оправдать аудит, запрещено.

Компромисс: требование пути эксплуатации отсекает шум и делает каждую находку проверяемой, но аудитор может пропустить реальную слабость, для которой пока не сумел построить конкретный сценарий; навык честно ставит порог именно здесь.

7. test-writer: тест, который не падает, ничего не проверяет

Одиннадцать шагов, и один из них — сломать код и убедиться, что тест это заметил.

Ключевая мысль: тест должен падать на сломанном коде

Остановись на секунду и ответь себе честно: когда ты последний раз ломал код специально, чтобы посмотреть, покраснеет ли тест? Тимур ответил «никогда» — и именно поэтому седьмой шаг test-writer стал для него главным.

Навык начинается с принципа: покрытие — инструмент, а не цель. Каждый тест существует потому, что без него уйдёт конкретный баг. Не можешь назвать этот баг — удали тест.

Одиннадцать шагов, ключевые из них:

  1. Точно определить, что тестируешь: публичный API, входы, выходы, побочные эффекты.
  2. Выбрать самый узкий тип: unit для чистых функций, integration для базы и файлов, e2e — только для критичных путей вроде входа и оплаты.
  3. Перечислить случаи: счастливый путь, граничные значения, крайние случаи, ошибки, идемпотентность.
  4. Тестировать контракт, а не реализацию: утверждения о результате, а не о внутренних вызовах.
  5. Фикстуры под задачу, а не одна гигантская на всё.
  6. Проверить, что тест падает на сломанном коде. Сломай реализацию — мысленно или по-настоящему — и убедись, что тест это ловит. Тест, зелёный при любой реализации, ничего не стоит.
  7. Имя теста описывает поведение системы: «returns 401 when token is expired», а не «test auth».

Ориентиры по времени из навыка: unit-тест — до 100 мс, интеграционный — до 2 с; дольше — значит, тест проверяет слишком многое за раз.

И последнее правило, про которое легко забыть: тесты надо запустить. Навык не разрешает заявлять «проходят», не запустив.

Компромисс: проверка «падает ли тест на сломанном коде» удваивает время на каждый тест, зато отсекает самый дорогой класс тестов — те, что годами зелёные и никого не защищают.

8. ci-fix и debugging: причина, а не симптом

Красный CI: как найти настоящую строку отказа и не спрятать проблему.

Ключевая мысль: чинить причину, а не симптом

Сюрприз, с которого начал Тимур: самый быстрый способ сделать CI зелёным — и самый запрещённый в этом пакете — одна строка. || true. Или continue-on-error: true. Или --no-verify. Навык ci-fix перечисляет все три и запрещает каждую: они не чинят, они прячут.

Вместо этого — десять шагов, из которых пять решают исход:

  1. Найти настоящую строку отказа. Лог на тысячи строк; ищи Error, FAIL, exit code, panic. Первый настоящий отказ — причина, всё после него может быть каскадом.
  2. Классифицировать: сборка, тест, линтер, деплой или инфраструктура (диск, OOM, сеть). От класса зависит, кого чинить — код или окружение.
  3. Воспроизвести локально с теми же версиями инструментов.
  4. Сверить окружения. Linux против macOS, регистр в путях, версия Node из .nvmrc, TZ=UTC в CI, параллельный запуск тестов, локаль.
  5. Чинить причину, а не симптом. Тест падает из-за часового пояса — сделай его независимым от пояса, а не пропускай. Не хватает зависимости — добавь в package.json, а не в CI-скрипт. Ошибка типа — почини тип, а не ставь @ts-ignore.

Родственный навык debugging говорит то же самое про ошибки выполнения: воспроизведи → прочитай ошибку целиком (стек читают снизу вверх; код выхода 137 — OOM, 139 — segfault) → сузь бисекцией → сформулируй опровержимую гипотезу → одно изменение за раз → почини на правильном слое. Запрещены заплатки: null-проверка в каждом вызывающем, try-catch вокруг всего, «магические» повторы, тихие значения по умолчанию.

И ещё одно, что Тимур раньше не делал: проверь, не красный ли main сам по себе. Если да — отказ старше твоего PR, и чинить его в PR — трата времени.

Компромисс: чинить причину дольше, чем спрятать симптом, — иногда на часы; зато спрятанный отказ вернётся в другом месте, дальше от причины и дороже.

9. database-migration: expand-contract без простоя

Почему нельзя переименовать колонку одной командой и как это делают за шесть шагов.

Ключевая мысль: expand-contract: миграция без простоя

Тимуру прилетела задача на вид пустяковая: переименовать колонку email в email_address в таблице users. Одна строка SQL — ALTER TABLE users RENAME COLUMN email TO email_address. Он уже занёс руку. И тут навык database-migration показал ему, что будет через секунду после этой строки: старые экземпляры приложения, которые ещё не перезапущены, начнут падать — колонки email больше нет.

Основа навыка — паттерн expand-contract: миграция без простоя, где ломающее изменение никогда не делается за один шаг. Вот он в коде, ровно как в SKILL.md:

  1. EXPAND — добавить новую колонку: ALTER TABLE users ADD COLUMN email_address VARCHAR(255); (для nullable-колонки в PostgreSQL это мгновенно, без блокировки).
  2. BACKFILL — скопировать данные пачками: UPDATE users SET email_address = email WHERE email_address IS NULL; — на большой таблице по 5–10 тысяч строк за раз, с паузами.
  3. DUAL-WRITE — выкатить код, который пишет в обе колонки.
  4. SWITCH-READ — выкатить код, который читает из новой.
  5. STOP-WRITE — выкатить код, который пишет только в новую.
  6. CONTRACTALTER TABLE users DROP COLUMN email; — только когда ни одна версия кода её не читает.

Порядок деплоя следует из паттерна: расширение схемы — до кода, сжатие — после кода, и никогда одновременно.

Ещё три правила из навыка, которые Тимур записал:

  • индексы в PostgreSQL создают только CREATE INDEX CONCURRENTLY — обычный CREATE INDEX блокирует таблицу;
  • у каждой миграции есть план отката, написанный ДО запуска; DROP COLUMN и DROP TABLE необратимы — восстановить можно только из бэкапа;
  • миграцию тестируют на данных производственного размера: пять секунд на 100 строках превращаются в 45 минут блокировки на 50 миллионах.

Компромисс: expand-contract растягивает одно переименование на несколько деплоев и дней, зато ни одна версия приложения ни на секунду не видит схему, которой не ожидает.

10. observability: гейт открывает файл, а не верит числу

История версии 0.3.9: как один шаг из десяти сертифицировал самоотчёт и что с этим сделали.

Ключевая мысль: гейт открывает файл дашборда, а не верит числу

Посмотри сначала на схему «до» и «после» рядом с текстом, а потом читай, как Тимур сам наступил на левую половину.

Навык observability — десять шагов, и девять из них выдают запускаемый артефакт: конфиг OpenTelemetry, правило алерта, SLO в YAML. Шаг 6 — дашборды — до версии 0.3.9 выдавал только таблицу и советы по компоновке. А выходная схема требовала число panels_count. Вот что проходило валидацию с нулём построенных панелей:

{ "name": "Payments", "type": "golden_signals", "panels_count": 6 }

Детерминированный прибор сертифицировал число, которое кто-то напечатал. README называет это инверсией, ради предотвращения которой существует лестница стоимости обнаружения: гейт, что падает на испорченном артефакте, но молчит на отсутствующем — здесь он даже до «испорченного» не доходил, потому что ничего не открывал.

Что изменилось в 0.3.9:

  • поле file стало обязательным — путь к JSON дашборда, который шаг реально записал;
  • scripts/check-dashboards.mjs открывает каждый файл: валидный JSON, непустой panels, и panels_count сверяется с реальной длиной, а не принимается на веру;
  • сам шаг 6 показывает, какой файл писать, и называет три недекоративные вещи в нём: "datasource": "${DS_PROM}" — переменная-шаблон, а не литеральный uid; "unit": "s" — потому что метрика оканчивается на _seconds; sum by (le) внутри histogram_quantile — усреднять готовый квантиль по инстансам арифметически бессмысленно.

Запуск: node observability/scripts/check-dashboards.mjs <output.json> --root <repo> — коды выхода 0 PASS · 1 FAIL · 3 NOT-ESTABLISHED, и NOT-ESTABLISHED никогда не считается проходом: гейт, который не смог запуститься, обязан сказать это вслух.

Равно важно, чего гейт НЕ доказывает — README ограничивает его честно: он не проверяет правильность запросов, не знает, испускаются ли метрики вообще, и не защищает от намеренного обмана. Четыре раунда ревью были лестницей: regex по тексту обошли через \u0064, panels:[null] — через panels:[{}]. Если автору отчёта нельзя доверять, это не тот прибор.

Компромисс: гейт, который открывает файл, ловит небрежного автора («заявил шесть панелей, построил ноль») и стоит одну команду, но ложится в структурный пол — смысл панелей всё ещё судит человек или кросс-модельное ревью.

11. Инцидент, проблема, известная ошибка

Три навыка эксплуатации — incident-response, problem-management, itsm-itil — и одна цепочка тикетов.

Ключевая мысль: инцидент восстанавливает сервис, проблема убирает причину

История одного дежурства. В 14:12 Тимуру прилетает алерт: checkout отдаёт 500-е, третий раз за месяц. Что он делает первым — ищет причину или восстанавливает сервис?

Три навыка пакета отвечают на этот вопрос хором: инцидент восстанавливает сервис, проблема убирает причину. Это две разные работы в разное время.

  • incident-response — про инцидент: подтвердить, классифицировать (SEV1 — полный отказ или потеря данных, SEV2 — сломана крупная функция, SEV3 — есть обходной путь, SEV4 — косметика), собрать роли, триаж, смягчить до поиска причины (откат, флаг, масштабирование), сообщать по расписанию, и только потом — разбор причины и постмортем в течение 48 часов, без поиска виноватых.
  • problem-management — про проблему: одна проблема может быть причиной многих инцидентов. Запись проходит состояния open → under-investigation → known-error → verifying → closed (плюс parked для отложенных). Известная ошибка (known-error) — это подтверждённая с доказательствами причина ПЛЮС записанный обходной путь; без обходного пути статус остаётся «в расследовании». Закрыть можно только проверенный фикс.
  • itsm-itil — связка: четыре типа записей (инцидент, проблема, известная ошибка, изменение/RFC) как Markdown-тикеты прямо в репозитории — docs/incidents/, docs/problems/, docs/changes/ — со ссылками друг на друга.

Что чинить первым, когда проблем несколько, решает WSJF — Weighted Shortest Job First: WSJF = Cost of Delay / Job Size. Пример из навыка: известная ошибка «5xx на checkout» — стоимость задержки 20, размер работы 2, WSJF 10; «редкая гонка при ротации логов» — 8 / 8 = 1. Первой чинят первую, хотя вторая звучит страшнее.

В упражнении Тимур проходит эту цепочку от алерта до закрытия — реши за него на каждом шаге.

Компромисс: разделение инцидента и проблемы требует двух записей вместо одной и дисциплины переводить статусы; зато пять «разных отказов» перестают маскировать один незакрытый дефект, а обходной путь ждёт дежурного в известной ошибке, а не в чьей-то памяти.

12. deploy-on-cloudru-vm: от ссылки на репозиторий до URL

Пять шагов протокола и правило: успех объявляется после verify, а не по коду выхода deploy.

Ключевая мысль: cloudru-vm verify после deploy

Тимур получает от коллеги ссылку на репозиторий и просьбу: «разверни на ВМ в Cloud.ru и дай ссылку». Раньше это был вечер. С навыком deploy-on-cloudru-vm — один разговор с агентом.

Разделение труда, как его описывает сам навык: CLI cloudru-vm (MIT, Go) берёт docker-compose-проект и делает всё тяжёлое — аутентификация → создание ВМ → плавающий IP → SFTP → docker compose up -d → health-check. Навык поставляет то, чего CLI намеренно не делает: анализ репозитория, синтез compose, сбор учётных данных и честную проверку.

Пять шагов протокола:

  1. Клонировать и понять репозиторий. Есть ли рабочий compose? Только Dockerfile? Ничего — тогда определить стек по package.json / requirements.txt / go.mod, порт, переменные окружения, внешние сервисы.
  2. Обеспечить docker-compose.yml. Есть — использовать; только Dockerfile — обернуть; ничего — синтезировать оба файла. Синтезированное показать пользователю до деплоя; секреты — спросить, никогда не выдумывать.
  3. Собрать четыре учётные данные Cloud.ru: CLOUDRU_KEY_ID + CLOUDRU_SECRET, CLOUDRU_PROJECT_ID, CLOUDRU_REGION (подсказать через cloudru-vm list-zones), CLOUDRU_IMAGE_ID (через cloudru-vm list-images --json, предпочесть Ubuntu LTS). Чего нет — спросить по имени, всё сразу.
  4. Задеплоить: cloudru-vm deploy -f docker-compose.yml --json. Повторный запуск с неизменённым хэшем compose пропускает создание ВМ.
  5. Проверить честно и передать подключение. cloudru-vm status, потом cloudru-vm verify — HTTP-проверка открытых портов; если упало — cloudru-vm logs -n 50.

Правило, ради которого Тимур запомнил этот навык: успех не объявляется по коду выхода deploy. Приложение может подняться и быть сломанным — плохой env, непрошедшие миграции. Отчёт пользователю — только после verify, или ровно то, что упало, с выдержкой из логов.

В конце Тимур отдаёт коллеге три строки: App: http://<public-ip>:<port>, SSH: ssh -i .cloudru-vm/id_ed25519 user1@<public-ip> и команды status | logs -f | destroy. И напоминает: каталог .cloudru-vm/ содержит приватный ssh-ключ — в git ему не место.

Компромисс: протокол задаёт лишние вопросы (учётные данные, подтверждение синтезированного compose) и не подходит для Kubernetes-образных нагрузок — это одна ВМ с compose; зато ни один секрет не выдуман и ни один «успех» не объявлен по коду выхода.

13. Подпись, канонический источник и ярусы доверия

Три «боковых» темы README, без которых пакет нельзя обновлять спокойно.

Ключевая мысль: подпись покрывает только файлы из тарбола

Три темы, которые в README выглядят приложениями, а на деле решают, можно ли пакету доверять и как его обновлять. Тимур пропустил их при первом чтении — и через неделю получил от проверки подписи слово TAMPERED.

1. Что покрывает подпись. Манифест .dz-manifest.json пакета покрывает ровно те файлы, которые пакет ОТГРУЖАЕТ — как их сообщает npm pack — а не всё, что лежит в рабочем дереве автора. Раньше подписывались и файлы, исключённые из files[] (обычно CHANGELOG.md), и у каждого получателя проверка говорила «в манифесте есть, в пакете нет» — пакет читался как подделанный. Переподписать в любой более ранний момент не помогло бы: этих файлов в тарболе никогда не было. Содержимое при этом не менялось — изменилось только описание.

2. Канонический источник. Этот пакет — канонический источник DevOps-навыков (ADR-001 / ADR-002). Раскладка под платформу — через dz sync --canonical packages/skills-devops --project .. Запись аддитивна: существующие файлы никогда не перезаписываются без --force. Значит, твои локальные правки навыка переживут обновление — и значит, обновления не приедут, пока ты сам не скажешь --force.

3. Ярусы доверия. В шапке каждого SKILL.md есть trust_tier. У десяти канонизированных навыков и большинства оригинальных — 2 («Validated»): есть schemas/output.json, scripts/validate-config.json, evals/<skill>.yaml. У deploy-on-cloudru-vm и itsm-itil1 («Structured»), и у первого прямо записан путь наверх: «Run /bto-test to promote to Tier 2». Ярус — не оценка полезности, а степень проверенности.

И последнее из README, что Тимур пересказывает коллегам: 0.3.9 вышла после чистого независимого раунда — шесть раундов кросс-семейного ревью дали C, C, D, C, затем A без находок; десять дефектов в 115 строках нового гейта закрыты, каждый закреплён тестом с тем самым входом, который его вызвал. Задержку сняли потому, что условие выполнено, а не потому, что терпение кончилось.

Компромисс: подпись только по тарболу и аддитивная синхронизация делают обновление предсказуемым, но требуют от тебя знать про --force и про то, что README в разделе Status может отставать от package.json (там сейчас 0.3.17).

Частые вопросы

Как поставить пакет и как обновиться?

Впервые: dz init --target claude-code --preset devops (все 30 навыков) или --select с именами через запятую. Обновление канонического источника: dz sync --canonical packages/skills-devops --project . — запись аддитивна, существующие файлы не перезаписываются без --force. Страница пакета: https://www.npmjs.com/package/@dzhechkov/skills-devops

Мне нужен навык, но я не знаю его имени. Что делать?

Назови задачу словами предметной области — навыки включаются по триггерным фразам из шапки SKILL.md. Посмотреть каталог руками: dz registry search <слово>; посмотреть точные триггеры и файлы навыка: dz info <skill-id>.

pr-review, security-audit и codeql-fix — в чём разница?

pr-review — общее ревью PR, безопасность там одно из восьми измерений. security-audit — аудит всего изменения по восьми категориям, с путём эксплуатации у каждой находки. codeql-fix — одна конкретная SAST-находка: реальна ли она и какой минимальный фикс. Каждый навык в разделе «When NOT to use» сам отправляет тебя к соседу.

Сервис лежит прямо сейчас. Какой навык?

incident-response: восстановить сервис (откат, флаг, масштабирование) до поиска причины. Когда сервис восстановлен и инцидент повторяется — problem-management: проблема, известная ошибка с обходным путём, очередь по WSJF. itsm-itil связывает их в Markdown-тикеты в репозитории.

Что проверяет гейт check-dashboards и чего он не проверяет?

Проверяет: каждый заявленный file существует, парсится как JSON, содержит хотя бы одну панель с типом; panels_count совпадает с реальной длиной. Не проверяет: правильность запросов, наличие метрик в живом источнике, устойчивость к намеренному обману. Коды выхода: 0 PASS, 1 FAIL, 3 NOT-ESTABLISHED — и последний никогда не проход.

Какая версия пакета актуальна?

В package.json на момент написания курса — 0.3.17. Раздел Status в README пакета отстаёт (там v0.3.0), а история версии 0.3.9 с гейтом дашбордов и областью подписи описана в самом README. Смотри версию в package.json или на странице npm.

Что такое trust_tier в шапке навыка?

Степень проверенности, а не полезности. 2 «Validated» — есть schemas/output.json, scripts/validate-config.json и evals/<skill>.yaml. 1 «Structured» — навык структурирован, но валидацию до яруса 2 ещё не прошёл; у deploy-on-cloudru-vm путь наверх записан прямо в шапке.