Семинар 5. Когда просьбы недостаточно: барьер и загрузка по требованию¶
Семинар 5 · ~89.75 мин · 68 слайдов
01 · Файл инструкций — это просьба: агент его читает и может не выполнить; рядом с ним ставится механизм, который срабатывает самостоятельно, и механизм, который загружается по требованию¶
Всё, чем настроен агент в этом проекте, — двадцать четыре строки текста. Он их читает. Исполнять их некому.
Файл инструкций — это просьба. Весь сегодняшний час стоит на одном вопросе: что поставить рядом с ней, чтобы правило исполнялось без доброй воли агента.
Задержитесь на слове «рядом». Файл остаётся как есть, к нему добавляется слой, который срабатывает сам.
Внизу пять таких слоёв. Два залиты: их мы сегодня заведём и проверим. Три пунктиром — они на следующем занятии.
Справка.
Про «так напишите правило жёстче». Эта мысль появляется первой и она законная. Говорю, что мы её проверим на этом репозитории через несколько слайдов и увидим, докуда её хватает. Раньше времени не опровергаю: на этой проверке стоит весь первый кейс.
Почему речь на обложке короткая. Слот — сорок пять секунд, и это весь бюджет слайда. Всё, что сюда не влезло, лежит ниже и берётся по месту, если зал даст паузу.
Про пять сегментов внизу. Каждый срабатывает по-своему и ломается по-своему. Два залитых различаются уже тем, кто их запускает: один срабатывает сам, второй агент открывает себе сам. Имена и определения — через два слайда.
Про объём этой заметки. Речевая часть короче ста двадцати слов намеренно: в сорок пять секунд больше не входит.
Откуда двадцать четыре строки. Файл инструкций демо-репозитория, ветка main: двадцать четыре строки, девятнадцать непустых, четыре раздела. Репозиторий публичный, сосчитать можно самому. Это размер настоящего файла, с которым занятие работает весь час.
Если спросят, почему именно пять. Пять — все слои, которые сегодня можно поставить рядом с файлом инструкций, не меняя сам файл. Шестой назовут — разбираем на перерыве.
Если спросят, зачем два, а не все пять за раз. Каждый из двух мы ещё и замерим: посмотрим, что он обещает и что делает. На пять таких замеров часа не хватит. Пять незамеренных механизмов — это и есть состояние, из-за которого занятие собрано.
Если спросят, при чём тут прошлое занятие. На нём этот репозиторий собрали, и на последней сцене агент записал в главную ветку вопреки записанному правилу. Начинаем мы с этого места, но знать прошлое занятие для участия не нужно: всё необходимое напечатано на следующем экране.
02 · Репозиторий, с которым работает занятие, — рабочий прототип с продуктовым, конфигурационным и документационным слоями, и каталога .claude/ в нём нет вовсе: ни хука, ни скилла, ни субагента¶
signup-landing — статический лендинг с формой заявки на демо-урок. Готовым он считается, когда сборка завершается с кодом 0, набор тестов проходит полностью и форма отправлена вручную — в заполненном и в пустом виде.
Смотрим, из чего он состоит. Наверху — что строим: описание, спецификация, журнал решений. Рядом файл инструкций и ссылка на него под вторым именем: этим настроен агент. Ниже каталог решений и задачная память. Внизу сам продукт и тесты к нему.
Масштаб файла инструкций держите в голове: двадцать четыре строки, девятнадцать непустых, четыре раздела. Один из четырёх разделов нам понадобится уже на первой развилке.
Теперь последняя строка, и она здесь важнее всего остального. Каталога .claude/ в этом репозитории нет: ни хука, ни скилла, ни субагента, ни настроенного сервера. Механический слой мы заводим с нуля.
Адрес под деревом настоящий, репозиторий публичный: дерево в нём пересчитывается построчно.
Всё перечисленное — текст. Агент может его учесть. Может и не учесть.
Справка.
Что делают команды, которыми это дерево проверяется. git clone забирает репозиторий к себе целиком, вместе с историей. ls -a в корне печатает содержимое каталога, включая скрытые имена с точкой впереди, — без флага -a каталога .claude/ не было бы видно, даже если бы он там лежал. wc -l CLAUDE.md считает строки в файле инструкций, их двадцать четыре. Все три проверяются на своей машине за минуту.
Если спросят, почему двадцать четыре строки, а непустых девятнадцать. Пять строк — пустые разделители между разделами. Считаю обе величины, потому что дальше мы будем смотреть, насколько файл вырос, — а вырастет он содержанием, разделителей останется те же пять.
Если спросят про второе имя файла инструкций. Это символическая ссылка: один и тот же файл доступен под двумя именами, чтобы его нашли разные инструменты. Содержимое одно, и правится оно в одном месте.
Если спросят, что такое задачная память в .tasks/. Каталог с файлами задач: что делается, что сделано. Он появился на прошлом занятии и к механическому слою отношения не имеет — это текст, как и всё остальное на этом экране.
Если спросят, что такое ADR в листинге. Запись архитектурного решения: по файлу на решение — что выбрали, из чего выбирали, почему. Здесь их три и шаблон для новых. Имена трёх не называю: в сверенном источнике список обрезан, и выдумывать их на занятии я не буду.
03 · Рядом с файлом инструкций ставят пять механизмов, и различаются они тем, кто приводит каждый в действие: среда, сам агент, внешняя система, отдельная роль, порядок работы¶
Рядом с файлом инструкций можно поставить пять разных механизмов. Прежде чем выбирать между ними, договоримся, что каждый из них такое — по одной строке, без устройства.
Хук — команда, которую среда запускает сама, в заданный момент работы агента. Агента об этом не спрашивают.
Скилл — процедура, записанная отдельным файлом. Агент открывает её сам, когда она понадобилась.
MCP, Model Context Protocol — подключение к внешней системе. Через него агент достаёт данные, которых в репозитории физически нет.
Субагент — отдельная роль с урезанными правами. Её запускают на одну задачу и получают обратно только итог работы.
Процесс — порядок работы, записанный файлами: план, запись по ходу, проверка перед сдачей.
Третья колонка — привязано ли это к одному инструменту. Сегодня — факт. Переносятся три строки из пяти: у скилла и у доступа наружу формат опубликован, процесс — обычные файлы. У хука и субагента приём есть у всех, а запись у каждого своя. Почему граница здесь — скажу в конце.
Пять строк — пять разных ответов на один вопрос: кто приводит механизм в действие. У хука это среда, у скилла сам агент, у MCP внешняя система, у субагента отдельная роль, у процесса — заведённый порядок.
Справка.
Если спросят, почему так коротко. Здесь только обозначение. Устройство хука разберём перед первым кейсом, устройство скилла — перед четвёртым, и там будет по целому слайду на каждое. Сейчас хватит одной строки на инструмент: дальше она понадобится вся пятёрка сразу.
Если спросят, чем хук отличается от процесса. Хук срабатывает внутри одного действия агента и успевает вмешаться в него. Процесс живёт поверх всей работы и проверяется глазами и командами уже по её следам. Один механизм — момент, другой — порядок.
Если спросят, почему MCP латиницей. Это имя протокола, у него нет принятого русского имени. Раскрытие на слайде стоит ровно для того, чтобы буквы не остались тремя буквами.
Если спросят, откуда третья колонка. Проверка по документации поставщиков и текстам спецификаций, первое октября; семнадцать первоисточников, они перечислены в материалах. Разбор одного переноса целиком будет перед закрытием, на своём слайде.
Если спросят, можно ли обойтись одним. Можно, и большинство проектов так и живёт. Весь вопрос в том, каким и по какому сигналу, — это и есть содержание сегодняшнего занятия.
Если прозвучит «а что из этого мы ставим». Отвечаю, что про это говорим через слайд, и не называю ничего раньше времени: следующий слайд — вопрос, и ответ на нём даёт зал.
Порядок строк. Он тот же, что порядок карточек на следующем слайде и на повторе вопроса в конце. Менять его нельзя: на совпадении держится возврат.
04 · Выбор из пяти усилений, сделанный для этого репозитория и его состояния, а не вообще — и тот же вопрос прозвучит сегодня второй раз¶
Вопрос на экране, и слова для ответа у вас уже есть — все пять только что названы.
Держите ответ при себе. Я соберу три-четыре голоса и просто запишу, без оценки: правильного ответа здесь нет ни одного. Выбор зависит от того, какой сигнал в проекте уже прозвучал, а про сигналы мы сегодня и говорим.
И про второй раз я говорю дословно: этот вопрос прозвучит сегодня ещё раз, в самом конце.
Справка.
Что зал назовёт и что отвечать на каждое. Хук называют чаще других — те, кто уже ловил агента на нарушении: сигнал к нему пришёл на прошлом занятии, правило нарушено в последней сцене. Принимаю и записываю. Скилл — ответ тех, у кого файл инструкций разросся: сигнал настоящий, но придёт он по ходу сегодняшнего занятия, не раньше. MCP — ответ тех, кому агент нужен за пределами репозитория; половина этой ступени, дисциплина минимальных прав, вообще не ждёт сигнала. Субагент — одна и та же роль повторяется из сессии в сессию; сигнал приходит на следующем занятии. Процесс — заводится на день 0, независимо от проекта: утверждение агента «готово» — самоотчёт, и проверить его нечем, пока не записан порядок.
Если прозвучит «всё сразу». Отвечаю, что так и делают, и цена этому — пять механизмов, ни один из которых не проверен; сегодня мы заведём два и оба проверим.
Если ответ прозвучит про инструменты вообще. Возвращаю к дереву одним словом: «здесь». Вопрос про этот репозиторий, с его формой заявки, тестами и двадцатью четырьмя строками инструкций.
Если зал молчит. Называю сам первую карточку и спрашиваю, кто бы с неё начал. Дальше голоса идут.
Чего здесь не делаю. Не оцениваю ответы, не называю свой и не свожу к одному. Ответ по всем пяти зал получит не сегодня: сегодня закрываются два.
05 · Две ступени и шесть развилок: у каждой названа проблема, которую видит пользователь, и то, что на ней решается¶
Две ступени, шесть развилок — весь маршрут занятия.
Верхняя строка каждой карточки — то, что видит человек, работающий с агентом. Не название механизма и не его починка: симптом, с которым приходят. Агент не исполняет записанную процедуру. Проверка работала и молча перестала. Работа замедлилась из-за хуков. Под симптомом строка «решаем» — что именно на этой развилке выбирается.
Ответов на карточках нет ни на одной. На каждой развилке вы сначала отвечаете сами, и только потом видите разбор.
Внизу, за пунктиром, три ступени следующего занятия. Только имена: что они добавят в репозиторий, сегодня не называем.
И последняя строка, её стоит запомнить. К концу занятия дерево репозитория будет отличаться от того, что вы видели на втором слайде, ровно на две строки. Две — а не десять и не «каталог с настройками»: мы будем считать то, что реально добавилось.
Маршрут занятия на этом кончается. Дальше сразу первая развилка.
Справка.
Почему развилок шесть, а ступеней две. Ступень — это инструмент, развилка — решение, которое на нём принимается. У хука их три, потому что хук ломается тремя разными способами: не поставлен вовсе, поставлен и молчит, поставлен и мешает. У скилла тоже три: что выносить, по чему его откроют, брать готовое или писать своё.
Если спросят, почему именно эти шесть. Каждая взята из реальной работы с демо-репозиторием, и у каждой есть артефакт, который можно открыть. Придуманных развилок здесь нет.
Если спросят про три нижние ступени. MCP, субагент и процесс — следующее занятие целиком. Сегодня про них говорится только то, что они есть; доступ наружу решением владельца курса уехал туда полностью.
Про две строки разницы. Строки две, и это проверяемое число: файл настроек и самотест хука, оба подтверждены коммитом. Файл скилла — по плану, коммита у него нет, и на итоговом слайде это будет написано прямо.
Если спросят, зачем шесть развилок на два инструмента. Потому что инструмент сам по себе ничего не решает: решают выборы, которые на нём делаются. Шесть развилок — шесть таких выборов, и каждый встречается в работе чаще, чем сам инструмент.
Остаток себе. Выбор на каждой развилке делает зал, и ответ я предъявляю только после того, как он прозвучал. На слайде этого нет намеренно: когда понадобится ответ зала, я его спрошу.
06 · Процедура работы с репозиторием записана в инструкциях и загружена, а коммит всё равно уходит в главную ветку: решаем, чем заставить агента эту процедуру исполнять¶
Первая ступень. В проекте есть записанная процедура работы с репозиторием: задача — отдельная ветка, в главную напрямую не коммитим. Файл инструкций загружается в начале каждой сессии.
Процедура не исполняется. Коммит уходит в главную ветку в обычной рабочей сессии, через несколько минут после того, как файл был прочитан.
Собираем то, что заставит её исполняться. Сначала — что именно произошло.
Если спросят, почему нельзя просто написать правило громче: это ровно вопрос следующих двух слайдов, и у меня для него есть живой пример из репозитория этого курса, где громче уже некуда.
Если спросят, в чём разница с прошлым занятием: там мы учили агента, что делать, и проверяли результат руками. Здесь нам нужно, чтобы порядок держался без нашего участия, в каждой сессии и в каждом клоне проекта.
Если спросят, будет ли это работать на человека, набирающего команды руками: нет, и это один из трёх пределов, которые мы назовём в конце ступени.
07 · Запрет коммитить в главную ветку записан в файле инструкций проекта явно, файл загружен и прочитан — и коммит всё равно лёг в main¶
Проблема ступени в одной сцене.
Строка сверху — дословно из файла инструкций проекта. Не пересказ: раздел называется «Repository etiquette», и в нём написано, что ветка на задачу создаётся до первой правки, а прямо в главную не коммитим. Файл загружается в начале каждой сессии, и агент его прочитал.
Три шага одной рабочей сессии. Агент правит проверку формы — задача по делу, никто его не провоцировал и ничего особенного от него не требовал. Делает коммит. Ветку не создаёт — ни до правки, ни после. Коммит ложится в главную, и дальше сессия идёт как ни в чём не бывало.
Запрет записан, файл прочитан, процедура не исполнена. Это всё, что мы знаем на данный момент: ни причины, ни оценки у нас пока нет. Заметьте, что нарушения правил среды тоже нет — агент сделал обычную разрешённую команду.
Цена внизу. Показ заказчику назначен на завтра, и эта правка уезжает мимо ветки прямо в то, что он увидит.
Если из зала прозвучит «так напишите строку строже» — это ровно следующий ход, и мы его сделаем через слайд. Там я покажу, как выглядит строка, написанная настолько строго, насколько это возможно, и чем это кончилось.
Если спросят, почему агент её не выполнил: правило в инструкциях — это текст в контексте, который модель учитывает вместе со всем остальным контекстом. Вес у него не абсолютный. Правило соревнуется с задачей, с историей сессии, с тем, что было сказано последним.
Если спросят, не одиночный ли это сбой: ошибка случается не каждый раз. Воспроизводимо здесь другое — ничто не гарантирует её отсутствия. Вероятность не ноль, цена срабатывания высокая, и барьер нужен именно поэтому.
Если спросят, видно ли это в истории: видно постфактум. git log --oneline main покажет коммит, которого в главной ветке быть не должно, — после того как он там уже лежит.
Если спросят, почему в разделе три пункта, а на слайде один: остальные два про частоту коммитов и про переключение ветки отдельной командой. К второму мы вернёмся: он написан уже под хук.
08 · Хук — команда, которую среда запускает сама в заданный момент работы агента: событие задаёт момент, матчер отбирает вызовы, решение уходит обратно среде¶
Одна вещь, которая понадобится во всех трёх ближайших разборах.
Хук — это команда, которую среда запускает сама, в заданный момент работы агента. Агента об этом не спрашивают и ему об этом не докладывают.
Три понятия, и каждое отвечает на свой вопрос. Событие — когда запускается. Матчер — какие вызовы хук отбирает из всех, что идут мимо. Решение — что он отвечает среде. Устройство целиком разберём дальше, сейчас достаточно трёх слов.
Справа то, что решает исход всех трёх кейсов. Момент выбирают: хук можно поставить до вызова и можно после. От этого выбора зависит, что он успеет. Поставленный до — успевает вмешаться и об исходе не узнаёт. Поставленный после — видит результат, когда вызов уже состоялся.
И последнее. Хук — отдельная программа. Она видит ровно то, что ей прислали: имя инструмента, аргументы, каталог. Ни истории, ни того, что агент собирается делать дальше.
Если спросят, какие ещё бывают события: тридцать три, собранные в шесть групп — сессия, ход пользователя, вызовы инструментов, файлы, команда агентов, контекст среды. Нам нужно одно, из группы вызовов инструментов. Полную карту я покажу после первого разбора.
Если спросят, на чём пишется хук: на чём угодно, что запускается. Строка для оболочки прямо в файле настроек или отдельный исполняемый файл рядом. Описание вызова приходит ему на стандартный вход, решение он печатает на выход.
Если спросят, можно ли поставить два хука на одно событие: можно, и сработают оба, параллельно. Что происходит, когда они отвечают по-разному, разберём во втором кейсе.
Если спросят, видит ли хук всю сессию: нет. Один вызов в изоляции. Он не знает, что было до и что планируется после, и не видит соседние вызовы, если среда запустила несколько сразу.
Если спросят, узнаёт ли агент, что хук сработал: при запрете узнаёт — причину отказа ему показывают, и он может её учесть. При «разрешить» и при «спросить» причину видит только человек.
Если спросят, где лежит файл настроек: .claude/settings.json внутри репозитория, под контролем версий. Он едет с клоном — барьер ставится один раз на проект и достаётся всем, кто склонировал.
Если спросят, почему нельзя просто дописать правило в файл инструкций: это вопрос первого кейса, к нему и идём.
09 · Инструкцию можно написать настолько громко, насколько это возможно — в репозитории этого курса она так и написана, и механизма, который бы её исполнял, рядом с ней нет¶
Инструкция есть, и написана она настолько громко, насколько это вообще возможно. Строка сверху — из файла инструкций этого курса.
Она всё равно осталась текстом. Рядом с ней не стоит ничего: никакой проверки, которая бы её исполняла.
Выберите, что поставить рядом. Пять вариантов на карточках, все пять настоящие — и скажите, почему именно этот ход при четырёх соседних.
И сразу честно: одно из этих слов вы слышали пять минут назад, я сам его произнёс. Поэтому узнать его — ещё не ответ. Называйте момент, в который ваш ход срабатывает: именно по моменту пять карточек и расходятся. Три-четыре версии, любую беру.
Справка.
Про саму строку. Файл инструкций этого курса открыт, проверить можно на перерыве. Писана она заглавными, со словом «никогда» и отдельной оговоркой про мелкие правки — чтобы не осталось лазейки.
Про состав карточек. Каждый из пяти вариантов где-то применяют; ни один не придуман для контраста, соломенных среди них нет.
Если прозвучит защита на стороне сервера — это сильный ответ, придержу его до разбора: там у него своё место, и я скажу прямо, в чём он крепче нашего.
Если прозвучит «написать правило ещё раз, в другом файле»: такой ход есть, и он даёт ровно то же, что строка сверху. Это полезный ответ, он показывает границу между текстом и механизмом.
Если прозвучит «попросить агента самого себя проверять»: тоже реальная практика. Ограничение у неё то же, что у инструкции: проверяющий и нарушитель — одна и та же система, и оба решения принимаются в одном контексте.
Если прозвучит «запретить ему git целиком»: это четвёртая карточка, и она сработает. Цена — в разборе.
Если прозвучит «настроить правило в системе управления задачами» или «договориться в команде»: обе вещи работают на людей и не работают на то, что делает агент внутри сессии. Это хороший повод назвать границу: нам нужен механизм, который стоит в момент действия.
Если никто не называет вторую карточку: не подсказываю. Разбор на следующем слайде проходит по всем пяти, и ответ появится там.
10 · Все пять вариантов работают, у каждого названы случаи и ограничения; из этого сочетания и следует выбор — серверная защита держит правило крепче, хук держит его раньше, и сегодня мы разбираем агентов¶
Разбираю все пять. У каждого названы случаи, где он правильный ответ, и ограничения — из двух колонок вывод складывается сам.
Серверная защита. Работает там, где правило должно держаться независимо от того, кто и чем работает. Ограничение: узнаёт о нарушении после отправки, и настраивается она вне репозитория, другим человеком.
Хук. Работает там, где проверка нужна до выполнения команды — разрешить, запретить, спросить человека. Ограничения: видит только агента и проверяет форму команды.
Служебный каталог git. Правильный инструмент, когда команды набирает человек. Не версионируется: в каждый клон копируется руками.
Забрать право на git. Сработает, если агент не должен трогать историю. У нас он коммитит по делу.
Проверять руками. Работает, пока показов мало.
Теперь вывод. Первые две строки законны обе, и я это говорю прямо. На сервере правило держится крепче, в репозитории — раньше. Мы разбираем агентов, поэтому берём хук. Серверную защиту ставят поверх.
Если спросят, почему не взять сразу сервер: взять можно, и в рабочем проекте так и делают. На этом занятии он не подходит по двум причинам. Он не часть репозитория — его не покажешь склонировавшему и не отдашь вместе с проектом. И он не успевает: коммит в локальной истории уже лежит, а нам нужно, чтобы правка не ушла в показ.
Если спросят, зачем тогда вообще сервер: он закрывает то, чего хук не закрывает в принципе. Человек с терминалом, второй агент на другой машине, обход формой команды. В конце ступени я назову это прямо как потолок.
Если спросят про git-хук подробнее: он живёт в служебном каталоге, который не едет с клоном. Поставить его можно, и на одной машине он работает; задача «барьер стоит у всех, кто склонировал» им не решается. Живой пример — репозиторий этого курса: там такой хук лежит, исполняемый, и не запускался ни разу. Разберём это через четыре слайда.
Если спросят, можно ли сочетать: можно и нужно. Хук в репозитории, сервер поверх, список известных дыр записан. Это и есть честная сборка, и к ней мы придём к концу ступени.
Если прозвучит «а если агент сам себя проверит»: проверяющий и нарушитель оказываются одной системой, решение принимается в одном контексте. Получается то же правило, сказанное второй раз.
Если спросят, что значит «форм у одной команды несколько»: env git commit, /usr/bin/git commit, коммит на второй строке составной команды. Проверка на строку их не ловит. Это слайд про провал, он будет через четыре хода.
11 · Хук устроен из шести частей: где объявлен, когда запускается, что получает на вход, сам его код, чем отвечает и что среда делает с ответом¶
Вся конструкция сразу, шесть частей. Дальше мы разбираем их по одной, и я буду возвращаться к этому экрану.
Где объявляется — файл настроек внутри репозитория, под контролем версий. У каждой строки написано, что она делает: событие, матчер, что запустить, сколько ждать.
Когда запускается. Событий тридцать три, они собраны в шесть корзин, и в каждой корзине их несколько — счёт напечатан. Нам нужна одна корзина, вызовы инструментов, и из неё одно событие.
Что приходит на вход. Описание предстоящего вызова: какой инструмент, какие аргументы, в каком каталоге, в каком режиме прав.
Сам код — шестая часть, справа. Это обычная программа: строка для оболочки прямо в настройках или отдельный файл рядом.
Чем отвечает — два канала, и они разные. Код возврата принимает три значения. Объект решения — четыре состояния.
И что среда делает дальше: пять шагов от собранных аргументов до исполнения или отказа.
Если спросят про матчер подробнее: он решает, сколько раз хук сработает за задачу. Речь именно о числе срабатываний; скорость хука — отдельная величина. Эта формулировка понадобится в третьем кейсе.
Если спросят, почему код один не блокирует: так написано в документации среды — спецификации хуков не существует ни у одного поставщика. Код два — единственный, который блокирует сам по себе. Код один среда считает неблокирующей ошибкой и вызов пропускает, хотя по привычке Unix единица означает «упало». Так устроена среда; авторы хука здесь ни при чём.
Если спросят, что будет при коде два и одновременном решении «разрешить»: вызов всё равно заблокируют. Код два сильнее решения, напечатанного этим же хуком.
Если спросят, чем «поля нет» отличается от «разрешить»: «разрешить» снимает вопрос о правах. «Поля нет» означает, что хук решения не принял, и среда идёт обычным порядком — может и спросить, и отказать по своим правилам.
Если спросят, останавливает ли запрет агента: нет. Снимается один вызов — тот, на котором сработал хук. Агент продолжает работу и читает причину отказа — её при запрете показывают именно ему.
Если спросят про таймаут: это срок, который среда ждёт ответа. Что происходит, когда он вышел, разберём в третьем кейсе — там на этом стоит целый случай.
Если спросят, можно ли поставить два хука на одно событие: можно, сработают оба, параллельно. Как среда сводит их ответы — во втором кейсе.
Если спросят, на каком языке пишут хук: на любом, который запускается. Оболочка, Python, скомпилированный файл. Описание вызова приходит на стандартный вход, решение печатается на стандартный выход.
Если что-то на этом экране непонятно — спрашивайте сейчас. Дальше я буду на него ссылаться.
12 · Барьер проектируется в три хода и в этом порядке: на что реагировать, когда реагировать и как реагировать — третий ход и есть код хука, и решений в нём три, а всего их пять¶
Проектируем. Три хода, и порядок у них тот же, в каком устроен сам хук. Решений на этих трёх ходах пять — последний ход несёт три.
На что реагировать — это матчер. Четыре варианта, и решает здесь цена: чем шире матчер, тем чаще хук запускается впустую и тем дороже любая ошибка внутри него. К этой цене вернёмся в третьем кейсе.
Когда реагировать. «После» даёт запись факта, уведомление, откат. Предотвращения оно не даёт.
Как реагировать — это код, и внутри него ещё три выбора. Что считать нарушением: любую команду git, только коммит, только коммит в защищённой ветке. Чем отвечать: запретить, спросить человека, разрешить и записать. И третье, которое пропускают: что делать, когда проверка не смогла ответить — каталог ещё не репозиторий, ветка не определяется, нужной команды в системе нет.
Последняя строка. Разрешить молча значит остаться без защиты и при этом выглядеть защищённым.
Какой вариант берёте на каждой строке? Записываю, и на следующем слайде сверим с тем, что лежит в репозитории.
Если спросят, откуда хук вообще узнаёт команду: ему присылают описание предстоящего вызова на стандартный вход — имя инструмента, аргументы, каталог. Он эту строку читает. Как именно, показано на следующем слайде, в первом шаге файла.
Если спросят, почему матчер стоит делать узким: каждое срабатывание стоит времени, и это время умножается на число вызовов в задаче. Третий кейс целиком про этот счёт.
Если спросят, зачем вариант «любой инструмент»: он нужен для хуков, которые ведут журнал: все вызовы подряд, счётчик, аудит. Там широкий матчер по делу.
Если спросят, чем «спросить человека» отличается от «запретить»: «запретить» закрывает вызов и объясняет причину агенту. «Спросить» останавливает вызов и ждёт человека. В сессии без человека рядом «спросить» превращается в «ничего не произойдёт», пока кто-нибудь не вернётся.
Если спросят, какой ответ даёт наш барьер при отсутствии репозитория: «спросить». Вариант выбран сознательно, и в репозитории он снят прогоном — на каталоге без репозитория хук просит человека и молча ничего не пропускает.
Если прозвучит «а если хук сам упадёт»: это и есть пятая строка. Упавшая проверка не блокирует ничего, и снаружи её падение выглядит как успешное прохождение. Это слайд провала, он через два хода.
13 · Собранный барьер — одна запись в файле настроек: объявление, четыре шага кода и два ответа, и рядом с каждой строкой сказано, что она делает¶
Тот же файл, что вы сейчас спроектировали. Слева — номер блока с карты устройства, в середине строка файла, справа — что она делает.
Объявление, блок один. Событие: проверка срабатывает до исполнения вызова. Матчер: только команды оболочки. Таймаут: десять секунд.
Дальше четыре шага кода, блок шесть. Первый достаёт из описания вызова саму команду — одной строкой, как агент её собирался выполнить. Второй ищет в этой строке git commit: в начале или после разделителя, чтобы коммит внутри составной команды тоже попался. Третий спрашивает, репозиторий ли это. Четвёртый спрашивает имя ветки.
Два ответа, блок четыре. Репозитория нет — передаём решение человеку. Ветка главная — закрываем вызов, и причина уходит агенту.
Каждая строка делает ровно одно. Ни одна из них не знает про остальные.
Если спросят, почему шаг четыре именно symbolic-ref: привычная git rev-parse --abbrev-ref HEAD на репозитории без коммитов падает с кодом сто двадцать восемь. git symbolic-ref --short HEAD на том же репозитории отдаёт имя ветки и ноль. Разница в том, что упавшая проверка ничего не блокирует и снаружи выглядит пройденной.
Если спросят, как выглядит выражение проверки целиком: (^|[;&|]\s*)git\s+commit\b — то есть git commit в начале строки либо после точки с запятой, амперсанда или вертикальной черты. На слайде оно приведено сокращённо.
Если спросят, где взять файл: github.com/tellina-study/signup-landing-demo, ветка seminar-5-hook. Файл под контролем версий, в свежем клоне барьер работает сам, ставить ничего не надо.
Если спросят про тексты причин: они сокращены, целиком оба показаны во втором кейсе — там разбирается, чем барьер говорит «нет».
Если спросят, почему таймаут десять, а не шестьсот по умолчанию: это третий кейс целиком. Коротко: срок умножается на число срабатываний.
Если спросят, почему проверка не в .git/hooks: этот файл едет с клоном, служебный каталог — нет. Разбирали на разборе вариантов.
14 · Барьер стоит, а срабатывает не всегда: между объявлением хука и прочитанным ответом шесть звеньев, и каждое рвётся молча — у каждого своя проверка¶
Барьер мы собрали, и он стоит. Теперь неприятное: он срабатывает не всегда.
Мини-кейс сверху. Самотест проходит, файл на месте, а в главной ветке снова чужой коммит. И нигде ни одного сообщения об ошибке — ни в сессии, ни в выводе команд. Это и есть тихий отказ: отличить «сработал и пропустил» от «не сработал вовсе» штатным интерфейсом нельзя.
Поэтому — классификация. От объявления хука до прочитанного ответа шесть звеньев, и порваться может любое. Каждое рвётся молча, и у каждого своя проверка.
Первое: хука нет в настройках. Второе: запись есть, но среда её отклонила по схеме. Третье: матчер не совпал — регистр или опечатка. Четвёртое: скрипт не запустился. Пятое: не успел. Шестое: ответил, а среда ответ не прочла.
Порядок строк — порядок отладки. Идите сверху вниз: первое порванное звено объясняет всё, что ниже него.
И седьмое, которое поломкой не является: цепочка цела, проверка сработала и пропустила, потому что ищет форму команды. Это предел, и он на следующем слайде.
Если спросят про команды подробнее. /hooks — встроенный список: показывает каждый настроенный хук, его событие, матчер, полную команду и файл, из которого он взялся. claude doctor запускается вне сессии и разбирает файлы настроек: называет невалидные файлы и отклонённые записи. claude --debug-file пишет подробный журнал выполнения хуков в указанный файл — сам флаг в терминал ничего не печатает, журнал надо открыть. Ручной прогон: подаёте скрипту описание вызова на вход и смотрите код возврата и вывод, без среды вообще.
Если спросят, почему сломанный файл настроек — тихий отказ: в интерактивной сессии он не тихий, диалог показывается сразу. Тихим он становится в запуске без интерфейса: там диалога нет, файл или запись просто пропускаются. Разница по механике важная — реально тихо рвётся одна кривая запись внутри рабочего в остальном файла.
Если спросят про таймаут отдельно: вышедший срок на этом событии вызов не блокирует — хук отменяется, вывод отбрасывается, вызов идёт обычным порядком, как если бы хука не было. На переключении модели ровно наоборот: там таймаут блокирует.
Если спросят про самотест и что он на самом деле проверяет: он строит настоящее описание вызова и запускает ту же команду, которую сам вытащил из файла настроек. Поэтому он ловит правку этого файла, смену версии git, отсутствие jq, нестандартное имя главной ветки. Чего он не ловит — сказано в шапке самого файла: он собирает описание вызова по зашитым в него же образцам, поэтому если среда переименует поле, тест продолжит проходить, а барьер будет мёртв. Проверить это может только живая сессия.
Если спросят, какая строка в журнале выглядит дословно: «Hook output does not start with {, treating as plain text».
Если спросят, какие пять форм команды проходят мимо: нестандартное имя главной ветки, флаг рабочего каталога, абсолютный путь к git, префиксная команда, коммит на второй строке составного вызова. Шестая отклоняется. Разбираем на следующем слайде.
15 · Собранный барьер честно работает, пока правило выражается формой команды, нарушитель — агент, а форм конечное число; за каждым из трёх пределов стоит другой инструмент¶
Обобщаю ступень. Механизм разобрали по звеньям; теперь — докуда достаёт правило, когда механизм исправен.
Три условия, и за каждым стоит другой инструмент.
Первое: правило должно выражаться формой команды. «Не коммитить в главную» выражается. «Не делай рискованных правок перед показом» — суждение, механизировать его нечем.
Второе, его часто пропускают: хук видит только агента. Вы сами, руками, в терминале закоммитите в главную — хук этого события не увидит.
Третье: форм команды бесконечно много — оболочка раскрывает слова уже после ответа хука. Гнаться за формами бессмысленно: потолок ставят запретом на стороне платформы, а хук сужают до перечислимого.
Отсюда решение. Барьер ставим, дыры записываем и держим на виду, регулярным выражением их не закрываем.
Барьер стоит и умеет запрещать. А чем он говорит «нет» — и в какой момент?
Если спросят, чем это отличается от предыдущего слайда: там механизм мог не отработать — звено порвалось, и мы это ловим проверкой. Здесь механизм отрабатывает полностью, и всё равно правило не достаёт. Первое чинится отладкой, второе — другим инструментом.
Если спросят, что такое --no-verify: флаг, которым git commit пропускает собственные хуки git. Наш барьер стоит в среде агента, его этот флаг не отменяет, но если вы полагаетесь на хуки git, флаг их снимает. Это перечислимая дыра: её можно назвать и закрыть.
Если спросят про core.hooksPath: настройка, которая переназначает каталог с хуками git. Меняется одной командой, и после неё прежние хуки не вызываются. Тоже перечислимая.
Если спросят, зачем вообще ставить барьер, который обходится: он закрывает случайное; против умышленного он и не ставится. Агент не обходит проверку намеренно, он просто собирает команду иначе. Против умысла нужен запрет на стороне платформы, и это другой разговор.
Если спросят про суждение-правило подробнее: такие правила не выбрасывают, их держат текстом и проверяют человеком на ревью. Разделение полезное: механизируемое — в барьер, суждение — в ревью. Список известных дыр при этом становится частью документации проекта и перестаёт быть устным знанием.
16 · Проверка стояла, срабатывала и молча перестала — а файл её никто не трогал¶
Второй случай начинается с состояния, в котором виноватых нет. Проверка на месте, написана правильно, однажды проверена и работала. Файл её никто не редактировал. Она перестала срабатывать, и ни одного сообщения об ошибке при этом не появилось.
Разбираться будем до низа: что изменилось в среде, почему проверка этого не увидела, что с этим делают и как убедиться, что сделанное работает.
Если спросят, не повтор ли это первого случая: там правило не исполнялось с самого начала и мы ставили барьер с нуля. Здесь барьер уже стоит и однажды работал. Ломается другое: он продолжает ловить ровно то, на что его настроили, пока вокруг всё поменялось.
Если спросят, сколько времени прошло между «работало» и «перестало»: в разбираемом обращении — около двух недель, и всё это время никто ничего не замечал. Срок важен не сам по себе: внутри него не было ни одного сигнала, по которому стоило бы пойти и посмотреть.
Если спросят, чем этот случай кончится: решением, которое принимает зал, и проверкой, которой это решение подтверждают. Проверка тут не формальность — без неё принятое решение и неработающее решение выглядят одинаково, то есть никак.
Если спросят, почему я не называю инструмент в заголовке: потому что в работе вы его тоже не знаете заранее. Видно одно — барьер молчит, а нарушения идут. С этого места и начинается работа.
Если спросят, пригодится ли это тем, у кого хуков нет: да. Разбираемая ошибка живёт в матчере, записанном через имя инструмента. Она повторяется везде, где проверка опознаёт работу по имени вызова.
17 · Проверку на правки защищённых файлов поставили, прогнали на живой правке и забыли; две недели спустя правки в этих файлах идут, а проверка молчит — и в хуке никто ничего не менял¶
Пока только то, что видно снаружи.
Две недели назад проверку поставили и тут же убедились, что она работает: правку остановила, причину напечатала. После этого к ней не возвращались — обычное дело, барьер на то и ставят, чтобы о нём не думать.
Сегодня в защищённом файле обнаружились новые строки. Заметили случайно, глазами: ничего нигде не загорелось. И это важная часть картины — между «работало» и «перестало» не нашлось ни одной точки, в которой стоило бы пойти и посмотреть.
Пошли смотреть сами. Запись о проверке лежит на месте, файл с того дня никто не открывал, в журнале за две недели чисто. Виноватых нет, и сломанного тоже нет.
Ответа на этом экране нет, и до следующего слайда я его не покажу. Что заподозрите первым? Две-три версии, любую принимаю.
Если спросят, какие версии называют обычно: сломанный синтаксис в файле настроек, опечатку в матчере, обновление среды, выключенные хуки целиком, кто-то закомментировал и забыл. Все пять — рабочие гипотезы, каждая из них случается, и ни одна здесь не верна. Говорить это стоит после того, как они прозвучали от зала.
Если спросят, почему не заметили раньше: замечать было нечем. Сработавшая проверка печатает отказ, не сработавшая не печатает ничего — и «ничего» выглядит ровно так же, как «нарушений не было». Эту мысль мы доставали в первом случае и достанем ещё раз в конце этого.
Если спросят, проверяли ли вообще что-нибудь после установки: однократно, в день установки. Этого хватает, чтобы убедиться, что проверка написана верно, и не хватает, чтобы знать, что она работает сегодня. Разницу разберём на пределе применимости.
Если спросят, что значит «защищённый файл»: файл, правки которого в этом проекте идут только через подтверждение. Список проектный, не общий — у каждого он свой, и обычно в нём лежат настройки развёртывания, миграции и файлы сборки.
Если спросят, сколько правок прошло за эти две недели: в обращении счёт не вёлся, и это тоже часть картины — счётчика не было. Что считать и чем, разберём в третьем случае, там счёт прогонов и станет предметом разговора.
18 · Расширили права агенту; в новом режиме он стал править файлы командой оболочки, а матчер отбирает вызовы по имени инструмента и такого вызова не видит¶
Теперь что оказалось. Три звена, и каждое следующее тянется из предыдущего.
Первое. Изменили права. Кому — агенту в этом проекте. На что — запускать команды оболочки без подтверждения. Где — в режиме запуска сессии; файл хука никто не открывал, и это правда. Как — одним переключением, сразу на всю сессию.
Второе, и вот оно неочевидное. Режим хуки не глушит: документация говорит прямо, что проверка с запретом останавливает вызов и в нём. Происходит другое. В этом режиме среда добавляет агенту указание предпочитать команды оболочки. Агент перестал звать правку файла и стал делать ту же правку через sed — это команда, которая подменяет строку прямо в файле.
Третье. Матчер перечисляет имена инструментов. Правка и запись в перечне есть, оболочки нет. Проверка не сломалась — до неё просто не дошло.
И нижняя строка. У одной модели указание активно, у двух других нет.
Если спросят, зачем вообще включали этот режим: чтобы агент не переспрашивал на каждой команде. Причина бытовая и честная — режим включают ради скорости работы. Обходить проверки никто не собирался, и в этом вся неприятность: никто не принимал решения ослабить барьер.
Если спросят, что такое sed -i: потоковый редактор, который применяет правило замены к файлу. Ключ -i означает «править файл на месте», без копии. То есть результат ровно тот же, что у инструмента правки, — другой только путь, которым агент до файла добрался.
Если спросят, почему проверку не предупредили: предупреждать некому. Матчер — это строка в файле настроек, он ни за чем не следит и ни о чём не узнаёт. Совпало имя — запустились, не совпало — ничего не произошло, и «ничего не произошло» наружу не печатается.
Если спросят, не ошибка ли это среды: обращение по этому поводу заведено и закрыто. Обход известен — указание отключается настройкой. Но полагаться на это как на решение нельзя: режимов и указаний будет больше, а матчер по имени инструмента останется таким же хрупким.
Если спросят, как это ловится вообще: подробным журналом запуска — в нём видно, какой инструмент вызывался и с чем сверялся матчер. Команду назову на слайде свидетельств.
19 · Матчер перечисляет имена инструментов, а правка пришла командой оболочки и прошла мимо — что делают дальше¶
Пять ходов. Каждый из них кто-то уже делал у себя, и каждый в своём случае правильный.
Называйте любой и говорите, что он вам даст. Мне интереснее второе: из «что он даст» и вырастает выбор.
Если сойдётесь на одном сразу — скажите тогда, в каком случае вы взяли бы соседний.
И отдельно: эти решения друг друга не исключают. Можно назвать два, и пара тоже бывает верным ответом.
Если спросят, что значит «расширить матчер»: дописать в перечень имён ещё одно — команды оболочки. Проверка после этого запускается и на них.
Если спросят, чем от этого отличается «переписать логику»: матчер только отбирает вызовы, решение принимает скрипт. Переписать логику — значит смотреть на то, какой файл вызов собирается менять, и перестать опираться на имя инструмента. Тогда путь перестаёт иметь значение.
Если спросят, зачем второй хук, если можно расширить первый: потому что проверки разные по сути. Одна читает готовые аргументы правки — имя файла там лежит прямым полем. Вторая получает строку команды и должна разобрать её сама. Это две разные программы, и держать их в одной — лишняя работа. Второй довод практический: первый хук работает, и его не хочется трогать.
Если прозвучит «ничего не делать» — это честный ответ, и его надо разобрать вслух: он означает, что цена нарушения ниже цены починки. Здесь это не так, но сам ход законный, и в четвёртом случае мы его возьмём всерьёз.
Если прозвучит «запретить агенту оболочку совсем»: сработает и сломает работу — сборку и тесты агент запускает той же оболочкой. Это тот случай, когда барьер останавливает нарушение вместе со всем остальным, и цену такого хода мы назовём на пределе применимости.
20 · Все пять решений работают, у каждого названы случаи и ограничения; из сочетания следует выбор — расширить матчер и править логику следом, потому что проверка здесь одна¶
Разбираю все пять. У каждого названы случаи, где он правильный ответ, и ограничения — из двух колонок вывод складывается сам.
Расширить матчер. Работает, когда путей к одному и тому же действию несколько и все они перечислимы. Это одна строка в настройках. Ограничение двойное: перечень закрыт, и широкий перечень запускает проверку на каждом вызове оболочки. Запомните второе — в следующем случае мы посчитаем, во что это обходится.
Переписать логику. Проверяем предмет: какой файл правка трогает, а имя вызова перестаёт играть роль. Ограничение — предмет надо достать из строки команды, а форм у неё несколько.
Поправить инструкции. Работает на мягком правиле и работает рядом с барьером. В одиночку — текст, и чем это кончается, мы видели.
Поставить второй хук. Когда проверки разные по существу. Ограничение — сработают оба, и ответы надо свести.
Вернуть режим. Закрывает сегодня один способ, не класс.
Вывод внизу. Первое и четвёртое законны оба, и я говорю это прямо: разница в том, одна у вас проверка или две. Здесь она одна, поэтому расширяем матчер, а логику правим следом.
Если спросят, почему мы не обсуждаем момент и жёсткость — до вызова или после, запретить или спросить: потому что здесь ломается не это. Момент выбран в первом случае и выбран верно: до вызова и запретить — единственное сочетание, при котором правка просто не случится. Запрет после исполнения ловит факт и годится для отката и уведомления, но правка к этому моменту уже в файле. Предупреждение до вызова — снова текст. Всё это осталось верным, и ни одно из этого не спасло: проверка не дошла до решения вовсе.
Если спросят, можно ли взять сразу и первое, и второе: можно, и в большом проекте так и делают — широкий матчер и отдельный разбор команд оболочки в своём скрипте. Для нашей задачи это две программы там, где хватает одной.
Если спросят, не проще ли запретить агенту оболочку совсем: той же оболочкой он запускает сборку, тесты и установку зависимостей. Барьер остановит нарушение вместе с работой. Торга здесь нет — останавливается всё.
Если спросят про «вернуть режим» всерьёз: обход задокументирован в самом обращении — указание отключается настройкой среды. Как временная мера он честный; как решение он держится на том, что завтра никто не включит режим обратно.
21 · Матчер не совпадает четырьмя способами, и ни один из них не печатает ошибки; у каждого своя проверка, и принятое решение надо увидеть сработавшим¶
Решение принято. Теперь то, чем его проверяют, и то, во что обходится проверка пропущенная.
В первом случае была цепочка из шести звеньев от объявления проверки до прочитанного ответа. Здесь я раскрываю одно звено — то, где сверяется матчер. Четырьмя способами он не совпадает, и ни один из них не печатает ошибки.
Первое: опечатка или другой регистр. Сверяются строки. Проверка при этом видна в списке, выглядит установленной и не запускается никогда.
Второе — наш случай: имя правильное, инструмент другой.
Третье: перечень задан списком вместо строки. Это ошибка схемы, и среда отклоняет весь файл настроек целиком.
Четвёртое — то, что вы только что себе устроили, расширив перечень. Он теперь совпадает на каждом вызове оболочки.
И вывод внизу. Матчер, который ничего не отбирает, и матчер, которому нечего отбирать, снаружи неразличимы.
Если спросят, как заставить проверку отказать нарочно: взять случай, который она обязана остановить, и выполнить его. Отказ должен быть виден сразу — текстом причины. Негативный контроль не менее важен: взять случай, который она обязана пропустить, и убедиться, что он прошёл. Проверено только то, что проверено с обеих сторон.
Если спросят про журнал подробнее: ключ --debug-file сам в терминал ничего не печатает, журнал надо открыть отдельно. Строка, которую вы там ищете, называет имя инструмента и перечень, с которым оно сверялось.
Если спросят, почему третий способ стоит рядом с остальными, если он ломает файл целиком: потому что в интерактивной сессии он не тихий — диалог с ошибкой показывается сразу при старте. Тихим он становится в запуске без человека. Разницу мы называли в первом случае, и она того стоит: по-настоящему молча рвётся одна неверная запись внутри файла, который в остальном работает.
Если спросят, сколько совпадений набегает за задачу: это предмет следующего случая, там будет счёт и цена одного прогона.
Если спросят, какую из четырёх проверок делать первой: ту, что сверху. Порядок строк здесь тот же, что в цепочке первого случая, — сверху вниз, и первое порванное звено объясняет всё, что под ним. Начинать с журнала запуска, пока проверка даже не видна в списке, значит читать подробности о том, чего не произошло.
22 · Два хука на одном событии срабатывают оба и отвечают независимо; среда применяет их ответы в одном и том же порядке, и запрет в нём сильнее разрешения¶
Вы поставили второй хук рядом с первым. На правке через sed совпали условия обоих. Агенту при этом уйдёт один ответ — вот как среда его получает.
Первое. Запускаются обе проверки, одновременно. Они не знают друг о друге и ничего между собой не согласуют. Это важно: писать вторую, рассчитывая, что первая что-то уже решила, нельзя.
Второе. Среда читает коды возврата. Код два блокирует вызов, и блокирует даже против «разрешить», напечатанного той же самой проверкой.
Третье. Решения сводятся по старшинству. Запрет, отложить, спросить, разрешить — в этом порядке. Запрет одной перебивает разрешение другой.
Четвёртое. Если решения не дала ни одна, решения нет вовсе — и это не «разрешено». Среда идёт обычным порядком разрешений и может спросить или отказать по своим правилам.
Строка, которую стоит забрать: запрет сильнее разрешения. Два хука не договариваются — побеждает более строгий.
Если спросят, что такое «отложить»: нишевое решение для прогонов без человека. Проверка завершается аккуратно и говорит, что вызов можно продолжить позже. В интерактивной работе оно почти не встречается, но в старшинстве стоит и однажды попадётся — поэтому и названо.
Если спросят, можно ли остановить агента целиком, а не один вызов: можно, отдельным полем ответа. Оно старше любого решения по вызову и останавливает всю работу, не только вызов. В этой таблице его нет намеренно — здесь сводятся два ответа об одном вызове.
Если спросят, зачем вообще два хука, если старшинство всё равно отдаёт победу запрету: затем, что они проверяют разное. Первая читает готовые аргументы правки, вторая разбирает строку команды. Старшинство нужно для случая, когда одна промолчала, а вторая отказала; спорить им не о чем.
Если спросят, что будет при трёх и более проверках: то же самое. Порядок от их числа не зависит, и ни одна не получает преимущества оттого, что объявлена раньше в файле.
Если спросят, как увидеть этот порядок у себя: встроенный список покажет обе проверки с их условиями, а подробный журнал запуска — какая что ответила на конкретном вызове. Обе команды я называл на прошлом слайде.
Если спросят, не проще ли было поправить первый хук: проще, и разбор так и решил. Этот слайд о том, что бывает, когда выбрали иначе, — и это второй законный ход, у которого есть своя механика.
23 · Решение принято верно и перечень расширен — и расширенная проверка тремя задокументированными способами сама отдаёт вызов дальше: по сроку, по коду возврата и по уровню, на котором лежит поле решения¶
Решение вы приняли верно. Я это подтверждаю — и провал всё равно про него.
Три строки, в правой колонке одно и то же. Первая: проверка не уложилась в отведённый срок. Вызов ушёл дальше. И обратите внимание на связь с вашей же починкой: расширенный перечень совпадает теперь на каждом вызове оболочки, значит и срок выходит чаще, чем выходил до расширения.
Вторая: нет вспомогательной утилиты, скрипт умер на первой строке и отдал код один. Код один, как мы разбирали, ничего не блокирует.
Третья: поле решения положено снаружи обёртки. Разбор прошёл, поле отброшено, в записи сессии ни строчки. Внутри обёртки, где среда читает, пусто.
Теперь ради чего они собраны вместе. Вы приняли решение. Файл с расширенным перечнем лежит на месте, вы его видите. Но вызов прошёл, и запись сессии выглядит так же, как если бы всё работало.
Вывод: решение — ещё не барьер. Барьер — это решение плюс доказательство, что оно отказало громко хотя бы раз.
Если спросят, как лечится первая строка: увеличить срок — мера на один раз. Настоящая починка — сузить матчер обратно, чтобы проверка запускалась реже, или ускорить сам скрипт. Это целиком предмет следующего случая, там будут числа.
Если спросят, почему именно jq: это ходовая утилита для разбора ответа среды, её вызывают первой строкой скрипта. На машине разработчика она есть, на чистой машине или в сборочном окружении может не быть, и официальная подсказка по устранению неполадок называет это сообщение.
Если спросят, какой уровень вложенности правильный: решение лежит внутри поля hookSpecificOutput, рядом с именем события. Положенное на уровень выше, рядом с самой обёрткой, оно разбирается без ошибки и отбрасывается. Ошибка выглядит как опечатка в одну скобку и стоит целого барьера.
Если спросят про четвёртый адрес, которого здесь нет: та же проверка, объявленная в шапке субагента — в его собственном файле описания, — может не сработать, хотя она же в файле настроек проекта срабатывает. Обращение заведено и не закрыто. Я не выношу это на экран: субагенты — тема следующего занятия, и проверить этот довод сегодня нечем. Запомнить стоит одно: место объявления проверки — такой же её параметр, как матчер, и работает он не везде одинаково.
24 · Расширенного перечня достаточно, пока доказано, что проверка срабатывает на новом пути, и пока путей ровно столько, сколько в нём перечислено; за этим пределом опорой становится предмет правки¶
Решение принято. До какого момента его хватает.
Хватает, пока есть доказательство, что проверка срабатывает на новом пути. Не на старом — именно на том, которым агент ушёл. Без этого «запретить» и «пропустить» снаружи одинаковы, и мы это уже видели на трёх способах.
Доказательство не разовое. Среду обновили, права поменяли — проверяем заново.
Вторая строка про сам перечень. Он закрыт по построению: в нём ровно то, что вы в него вписали. Путь, которого в нём нет, проходит молча, и тогда опорой становится предмет правки.
Барьер отвечает правильно и вовремя. Сколько он стоит?
Если спросят, как именно заставить проверку отказать громко: берёте ровно тот путь, который чинили, — правку через команду оболочки, — и выполняете её на защищённом файле. Отказ обязан быть виден текстом причины. Потом берёте разрешённый файл и убеждаетесь, что правка прошла. Проверено только то, что проверено с обеих сторон.
Если спросят, почему «после каждой смены прав»: потому что именно смена прав этот случай и породила. Режим переключили ради удобства, барьер при этом никто не считал затронутым — и он перестал работать. Права и барьер связаны, хотя на вид лежат в разных местах.
Если спросят, что значит «проверять предмет» на практике: скрипт достаёт из описания вызова путь файла и сверяет его со списком защищённых. Для правки файла путь приходит готовым полем; для команды оболочки его надо разобрать из строки, и разбор этот честно сложный — формы у команды разные, и часть из них мы перечислили в первом случае.
Если спросят, не честнее ли сразу писать проверку по предмету: честнее и дороже. Начинают с перечня имён, потому что он делается за минуту; переходят к предмету, когда перечень перестал закрываться. Порядок здесь такой же, как с любым барьером: сначала дешёвое и проверяемое, потом точное.
25 · Барьеры стоят, отрабатывают исправно и не выдают ни одной ошибки — а работа идёт в разы дольше, чем шла месяц назад¶
Третий случай про то, что барьер может стоить дорого, оставаясь исправным. Ни одного сообщения об ошибке здесь не будет: всё, что мы увидим, — это время. Разбираться придётся с величиной, которую на занятии до сих пор никто не считал, хотя лежала она на виду с первого случая: сколько раз барьер запускается за одну задачу и во что это обходится.
Если спросят, почему замедление вынесено в отдельный случай, а не в примечание к первому: отказ и замедление опознаются по-разному и чинятся по-разному. Сломанный барьер даёт событие — пропущенную правку, отсутствующий отказ, запись в журнале. Дорогой барьер события не даёт вовсе: он честно отрабатывает каждый раз, и единственный его след — минуты, растворённые в рабочем дне. Такое не замечают неделями, а когда замечают, подозревают что угодно, кроме собственной проверки.
Если спросят, не противоречит ли заголовок тому, что сейчас будет на экране: заголовок называет инструмент, потому что мы третий случай подряд разбираем хуки и скрывать тут нечего. Чего в нём нет — причины: почему исправный хук начинает стоить час. Её разберём после того, как зал назовёт свои версии, и до разбора я её не произнесу.
Если спросят, чем этот случай связан с предыдущим: прямо. Во втором мы расширили матчер, чтобы проверка перестала пропускать правки через оболочку. Он стал шире — и запускаться проверка стала чаще. Цену этого я обещал посчитать; считаем здесь.
Если спросят, сколько времени займёт сам случай: столько же, сколько два предыдущих. Одна сцена, один вопрос залу, разбор, три замера и граница применимости. Файла решения в этом случае не будет — вместо него процедура измерения, которую можно применить к своему проекту в тот же день.
26 · До пересмотра процессов в репозитории задача занимала минуты; через несколько недель после пересмотра та же задача стала занимать час — и зал называет свои версии до того, как услышит причину¶
Пока только то, что видно по часам. Месяц назад задача такого размера занимала минуты. Сегодня она занимает час. Между этими двумя точками в репозитории пересмотрели процессы работы — что именно пересмотрели, пока отложим. Сама задача не изменилась: тот же проект, тот же размер правки, та же машина, тот же человек за ней. Ни одного сообщения об ошибке за это время не появилось, и чинить, судя по экрану, нечего: всё работает и всё отвечает. Просто дольше. На что подумаете? Назовите две-три версии, любую беру и ни одну не оцениваю.
Если спросят, что считается «задачей такого размера»: одна связная правка продукта — несколько файлов, несколько прогонов, коммит в конце. Единица, которой меряют рабочий день; отдельная строка кода такой единицей не бывает.
Если спросят, насколько точны «минуты» и «час»: это наблюдение; замера за ним нет. Секундомера в тот момент никто не держал, и делать вид, что держал, я не стану. Поэтому на схеме «было» нарисовано полосой: точка обещала бы точность, которой у меня нет. Измеренные цифры в этом случае будут, но позже и отдельно — и там я скажу, что именно измерено, а что посчитано.
Если прозвучат версии про медленную модель, сеть, большой контекст или разросшийся проект: все четыре — рабочие гипотезы, и каждая случается. Проверяются они одинаково: ищется то, что изменилось между двумя точками. Проект и машина те же, модель та же, сеть та же. Изменилось содержимое репозитория.
Если спросят прямо, не хуки ли это: отвечу, что посмотрим. Называть причину до того, как зал назовёт свои версии, здесь нет смысла — весь случай про то, как её находят.
Если спросят, почему пересмотр процессов вообще затевали: ровно затем, зачем мы занимались этим два случая подряд. Правило записали, барьер поставили, второй случай довели до рабочего состояния. Каждый шаг был правильным, и ни один не отменяется тем, что мы сейчас увидим.
27 · В журналах за одну задачу — десятки запусков хука, каждый запуск встаёт паузой, и внутри каждого проходит полный цикл проверок; ошибок при этом нет ни одной¶
Пошли смотреть журналы. Ошибок там нет ни одной — зато есть записи о запуске хука, и за одну задачу их десятки: запуск идёт почти на каждом шагу агента.
Каждый такой запуск — пауза: агент стоит и ждёт, пока внутри пройдёт полный цикл проверок. Цикл сам по себе не быстрый, и десятки таких прогонов складываются в тот час, который видно по часам.
Если среди версий прозвучал тяжёлый проект — проект тот же, что и вчера. Изменилось число запусков.
Считать будем через слайд: там появятся измеренные цифры, и я скажу, что именно замерено, а что посчитано.
Если спросят, где эти записи смотреть: журнал самой сессии агента, запуск с подробным выводом. Каждая строка о запуске помечена временем, и число запусков за задачу считается по этим строкам руками, без всякого инструмента. Процедуру целиком разберём на слайде про собственный замер, и она укладывается в один рабочий день.
Если спросят точное число запусков: оно будет через слайд, вместе с замером. На глаз их десятки при одном ожидаемом, и этого хватает, чтобы заметить порядок величины; точность здесь ничего не добавляет.
Если спросят, не замедлилось ли само окружение: смотрели. Машина та же, модель та же, сеть та же, размер проекта тот же. Изменилось только число записей о запуске.
Если спросят, почему в журнале нет ни одной ошибки: потому что ошибки и нет. Каждый запуск завершается успешно и сообщает об успехе. Отказа в этом случае не происходит вовсе: происходит трата, и платят её временем. Журнал про трату молчит — сообщать ему не о чем.
Если спросят, видно ли это без журнала: видно по часам и по собственному ожиданию — рабочий день просто кончается раньше, чем кончается задача. Но решение принимается по числу запусков, и ощущение этого числа не даёт — поэтому в журнал мы всё-таки заглянули.
28 · Задача идёт час, хук вызывается много раз и каждый раз долго, ошибок нет ни одной — что делаете и с чего начинаете¶
Пять ходов, и все пять в работе встречаются. Выберите, что делаете, и скажите, с чего начнёте. Три-четыре версии, любую беру и ни одну не оцениваю. Если прозвучит что-то шестое — тем лучше, запишем рядом. Ответ здесь может состоять из двух ходов, поэтому я и спрашиваю про начало: порядок тут весит больше, чем сам список. Напомню, что на экране: задача идёт час, хук вызывается много раз, каждый вызов долгий, ошибок нет ни одной. Чинить, строго говоря, нечего — всё работает.
Если спросят, что такое «вынести на пул-реквест»: прогнать проверку один раз, когда работа готова и предложена к слиянию, вместо того чтобы гонять её в момент каждой правки. Механизм для этого стоит вне репозитория; на разборе я скажу, чем за это платят.
Если спросят, можно ли выбрать сразу два: можно, и правильный ответ здесь как раз из двух. Между ними есть порядок, и он держится на одном рассуждении, которое мы сейчас и проделаем.
Если прозвучит «увеличить таймаут» — приму и придержу. На разборе этот ход окажется поучительнее остальных четырёх: ровно на нём расходятся «ждать дольше» и «работать быстрее», и смешивают их постоянно.
Если зал возьмёт «терпеть»: ход законный, и делать вид, что он ошибочный, я не стану. У него есть условие, при котором он правильный, и это условие мы назовём вслух.
Если прозвучит «переписать сам хук, чтобы работал быстрее»: хороший шестой вариант, на карточках его нет. Разберём вместе с остальными — он упирается в то, что ускорить проверку в разы обычно невозможно, а сократить число её запусков можно одной строкой настроек.
Если спросят, есть ли здесь ловушка: ловушки нет. Есть пять ходов, у каждого свои случаи и свои ограничения, и выбор складывается из их сочетания.
29 · Все пять ходов работают, у каждого названы случаи и ограничения; из сочетания следует, что сначала сокращают число срабатываний, а дорогие проверки уводят туда, где они идут один раз за задачу¶
Разбираю все пять. У каждого названы случаи и ограничения, и вывод складывается из двух колонок.
Терпеть. Работает, когда задержка короче разбирательства с ней. Ограничение одно и серьёзное: цена названа, но не посчитана.
Выкинуть. Работает, когда дорогую проверку уже делает другой барьер. Ограничение: уносит и то, что стоило миллисекунды.
Увеличить таймаут. Работает, когда проверка обрывается на полпути. Ограничение решающее: таймаут — это срок ожидания. Вышел срок, и вызов идёт дальше без проверки, молча. Длиннее срок — дольше ждёте и тот же тихий пропуск.
Сузить матчер. Работает, когда проверка нужна на одном действии из многих.
Вынести дорогое на пул-реквест. Работает для сборки, тестов, разбора кода.
Теперь вывод. Цена задачи — это число срабатываний, умноженное на цену прогона. Сужение бьёт по первому множителю одной строкой; ускорить второй в разы обычно невозможно. Поэтому сначала сужаем, потом уводим дорогое на пул-реквест.
Если спросят, почему сужение первое, а не вынос: потому что оно дешевле и обратимо. Это одна строка в файле настроек, её правят за минуту и так же легко откатывают. Вынос проверок на пул-реквест — это настройка механизма вне репозитория, согласование с командой и новый шаг в процессе. Делать дорогое раньше дешёвого есть смысл, только если дешёвое не помогает; здесь помогает, и сильно.
Если спросят цифры — они будут на следующем слайде, и там же сказано, что измерено, а что посчитано. Коротко: наш барьер ветки стоит двадцать семь миллисекунд за всю задачу, а сборка — тысячу двести семьдесят пять миллисекунд на каждой правке. Разница между ними не в скорости, она в числе срабатываний.
Если спросят, не теряем ли мы проверку, когда сужаем: теряем ровно на тех вызовах, которые из условия убрали, и это решение сознательное. Поэтому сужение требует замера: сначала смотрят, на каких вызовах проверка действительно нужна, потом режут остальные.
Если спросят про «переписать хук, чтобы работал быстрее»: законный ход, и иногда он срабатывает — например, когда внутри хука стоит лишний запуск сборки. Но потолок у него низкий: сократить прогон вдвое — удача, а сократить число прогонов в двадцать раз — одна строка.
Если спросят, можно ли сузить так, чтобы не потерять второй случай: можно, и это сочетание двух решений. Условие отбирает по действию, а внутри хука проверяется предмет правки. Тогда узкое условие не становится дырой.
30 · Наш узкий барьер стоит 27 миллисекунд за всю задачу, а тот же проект с матчером на любое изменение платит 51 секунду на сорока правках — множитель это число правок, а не цена одного прогона¶
Решение мы приняли. Теперь цифры, на которых оно стоит, и в них важно, где замер, а где счёт. Сверху цена одного срабатывания на настоящем проекте: наш барьер ветки — двадцать семь миллисекунд, сборка — тысяча сто тридцать семь, больше секунды. Главная колонка последняя: наш срабатывает один раз за задачу, сборка — на каждую правку. Снизу рост. Первая строка измерена от начала до конца: двадцать правок — двадцать шесть секунд, сорок — пятьдесят одна. Три остальные подписаны как арифметика. Считаю вслух, чтобы минуты не появились из воздуха: сорок правок по тысяче двести семьдесят пять миллисекунд — пятьдесят одна секунда. Добавьте прогон тестов на минуту — правка стоит около шестидесяти одной, сорок на шестьдесят одну даёт сорок одну минуту. Два хука — вдвое. Вот откуда час: он собрался из двадцати семи миллисекунд, умноженных не на то число.
Если спросят, почему строки с тестами не измерены: прогон тестов в песочнице, где снимались замеры, не работает — браузер не стартует. Честнее было пометить эти строки арифметикой, чем выдать время неудачной попытки за время рабочего прогона. В прошлой редакции одну цифру вывели счётом и подали как измеренную; её пришлось снять, и с тех пор на этом слайде помечена каждая строка.
Если спросят про схему: на ней обе строки лежат на одной линейке, и двадцать семь миллисекунд занимают на ней меньше пикселя. Это не брак рисунка, это и есть отношение — один к тысяче восьмистам восьмидесяти девяти. Поэтому отметка подписана словами: видимой полоской эту величину не нарисовать.
Если спросят, откуда взялись сорок правок: это верхняя граница задачи такого размера, двадцать — обычная. Обе колонки на слайде по этой причине и стоят рядом.
Если спросят, почему два хука: личный из домашних настроек и проектный срабатывают оба на одно событие. Это следующий слайд, там же и то, чего об этом никто не измерил.
Если спросят про внешние цифры для сравнения: у стороннего профилировщика простой хук выходит около тридцати миллисекунд, он же с опросом процессов — около четырёхсот сорока. Множитель там примерно пятнадцатикратный, у нас — два с половиной; расхождение зависит от числа процессов на машине и не сглаживается.
31 · Померить цену хука у себя — три шага: посчитать правки за задачу, умножить на цену прогона, сравнить с длительностью задачи; порог берётся как доля от задачи¶
Артефакт этого случая — процедура. Применить её можно к своему проекту сегодня, редактор для этого открывать не придётся. Начинают со списка хуков: команда показывает, какие стоят и с какими матчерами. В моём случае выяснилось, что часть хуков я не заводил, они приехали с настройками. Дальше самое дешёвое средство, которое чаще всего забывают: попросить агента прочитать отладочный журнал и сказать, какие хуки срабатывали и сколько заняли. Он работает с теми же файлами. Строка про time — главная по смыслу: команда меряет одно срабатывание, и её надо умножить на число правок за типичную задачу. Цифра за один вызов не отвечает ни на что: двадцать семь миллисекунд и тысяча сто обе выглядят приемлемо, различаются они множителем. И последнее средство — подробная запись отладки: она показывает каждый запуск построчно, с вызовом и ответом.
Если спросят про порог: абсолютного порога нет, и это содержательная часть ответа. Одна и та же цена — пятьдесят одна секунда — это восемь процентов десятиминутной задачи, почти треть трёхминутной и почти вся минутная. Вопрос здесь один: какая доля задачи. Число миллисекунд само по себе не отвечает ни на что.
Если спросят, что такое time: служебная команда оболочки. Запускаете через неё что угодно, и по завершении она печатает, сколько это заняло. Для хука запускают ровно ту команду, которая стоит в настройках, на своей обычной нагрузке.
Если спросят, чем профилировщик лучше: он снимает то же измерение разом по всем хукам и складывает результат в таблицу. Автор сторонний, в поставку среды он не входит, и ставить его ради одного замера необязательно.
Если спросят, сколько правок считать типичными: посчитайте по последним трём своим задачам. Число окажется устойчивее, чем кажется, и именно оно у вас множитель.
Если спросят, что делать с результатом больше десятой доли задачи: смотреть, какие вызовы в матчере лишние, и резать их. Это тот ход, который мы разобрали, — только теперь с цифрой в руках.
Если спросят, надо ли мерить каждый хук отдельно: надо, и складывать потом. Сессия платит сумму всех сработавших, и ровно об этом следующий слайд.
32 · Хуки разных уровней настроек складываются и срабатывают оба, поэтому измеренная вами цифра — не та, которую платит сессия; а суммарной латентности по флоту не измерил никто¶
Процедура с предыдущего слайда верна. И всё равно даст не тот ответ — вот почему. Списки хуков не перекрываются — они объединяются: это прямо в документации. Значит, ваш личный хук из домашних настроек и проектный хук на то же событие сработают оба. Следствие первое: вы измерили свой, а сессия платит за сумму. Следствие второе, про командную работу: владелец репозитория видит только проектные хуки. То, что участник завёл себе сам, ему не видно вовсе — ни измерить, ни учесть. Человек жалуется, что у него всё медленно, и оба правы. И то, чего я не нашла: сколько хуков в среднем стоит в реальном проекте и какова суммарная задержка по флоту — не измерено никем. Подставлять сюда похожие цифры из смежных работ я не буду. Поэтому отсюда забирают арифметику и способ считать.
Если спросят, где это написано: в разделе документации про настройки. Когда один и тот же ключ-список задан на нескольких уровнях, среда объединяет списки; выбрать один из них она не пытается. Хуки — тоже список, поэтому объединяются и они. И все совпавшие хуки запускаются параллельно.
Если спросят, сколько всего уровней настроек: пять, от личных до заданных на запуск, и у них есть порядок старшинства. Для цены это ничего не меняет: старшинство решает, чей ответ сильнее, а время тратят все сработавшие.
Если спросят, как увидеть сумму целиком: той же командой со списком хуков, но запущенной в том же окружении, в котором вы работаете. Она покажет и личные, и проектные. Разница между этим списком и содержимым файла проекта — и есть то, чего владелец репозитория не видит.
Если спросят, почему честный пробел стоит прямо на слайде, а не в оговорке: потому что он меняет, что отсюда уносят. Эталонного числа «сколько стоят хуки в среднем проекте» нет, контролируемого эксперимента никто не ставил. Уносят арифметику и способ считать — и считать придётся на своём проекте.
Если спросят, не преувеличение ли это: проверяется за минуту. Откройте список хуков у себя и посмотрите, сколько из них вы заводили сами.
33 · На каждом шаге проверяют то, что стоит миллисекунды и чего нельзя отложить; всё остальное проверяют один раз, когда работа закончена — а за пределом этого правила меняют саму проверку¶
Это то, что стоит унести с занятия, и сформулировано оно не про git. Колонки разведены по частоте. Важность их не делит. Слева то, чему надо сработать на каждом шаге; справа то, чему достаточно сработать один раз, когда работа закончена. Два вопроса, по которым сортируется любая проверка. Первый: если отложить её до конца — станет хуже? Запрет на опасное действие отложить нельзя, он тогда бесполезен. Сборку и тесты можно. Второй: сколько она стоит? Миллисекунды человек не замечает; секунда на шаге кажется мелочью, но на двадцати шагах это полминуты. Внизу пара чисел, чтобы правило не было абстрактным. И строка про предел: бывает проверка, которую отложить нельзя и которая всё равно стоит секунды. Сортировка её не спасает — тогда меняют саму проверку, и как именно, скажу через минуту.
Если спросят пример такой проверки: разбор большого файла настроек на каждое сохранение. Отложить нельзя — иначе агент весь час работает по сломанным настройкам; быстрее не делается — файл большой. Выход один: на каждом шаге проверять только изменившийся кусок, а полный разбор оставить на конец работы.
Если спросят, что считать «шагом»: любое действие агента, на которое настроен матчер, — правка файла, запись, команда оболочки. Шагов за задачу десятки, и это число и есть множитель.
Если спросят, почему двадцать три секунды здесь арифметика: потому что это тысяча сто тридцать семь миллисекунд, умноженные на двадцать правок, и только сборка. Измерена цена одного прогона, а произведение посчитано.
Если спросят, не противоречит ли это первому случаю, где мы барьер ставили: нет. Барьер ветки стоит двадцать семь миллисекунд и срабатывает один раз за работу — он в левой колонке по обоим признакам. Правило его не отменяет, оно объясняет, почему именно он оказался дешёвым.
Если спросят, куда в этой сортировке попадает проверка из второго случая: в левую колонку. Правка защищённого файла — это как раз то, что нельзя пропустить и нельзя отложить. Поэтому там мы матчер расширяли, а здесь сужаем: решает то, что под него попадает, — направление здесь ни при чём.
Если спросят, не слишком ли это общо: проверить легко. Возьмите любую проверку из своего репозитория и ответьте на два вопроса — можно ли отложить и сколько стоит. Две колонки покрывают почти всё; то, что не покрыли, попадает в строку про предел.
34 · Одно правило объявлено в файле инструкций дважды, копии разошлись — и агент читает обе в каждой сессии, включая те, где это правило ни при чём¶
Второй блок занятия: процедуры, которые живут отдельным файлом рядом с проектом. Начинаем с того, что видно без всякой теории.
В файле инструкций этого курса одно правило объявлено дважды. Копии написаны в разные дни и расходятся между собой. Агент читает обе в каждой сессии — и в той, где это правило вообще ни при чём. Что с этим делать, решаем вместе.
Если спросят, при чём тут предыдущий блок: там мы ставили барьеры — команду, которую среда запускает сама. Здесь речь о другом: о процедуре, которую надо выполнить по шагам, и которая лежит обычным текстом. Барьер и процедура — разные вещи, и путают их часто.
Если спросят, почему берём файл этого курса: потому что его можно открыть и проверить при мне. Все три находки следующего слайда снимаются четырьмя командами, и команды на нём напечатаны. Выдуманный пример такого не выдерживает.
Если спросят про счёт в теге: две копии одного правила — это сцена; четыре замера — то, чем мы потом проверяем собственный выбор; один провал — цена решения, которое мы примем. Все три числа прозвучат.
Если спросят, не слишком ли мелкая проблема: заметно она действительно не ломается, и никто с жалобой не приходил. Это свойство всего занятия — отказы здесь тихие. Цена этой тишины измерена, и мы её назовём, но после того, как зал скажет, что делать.
Если спросят, почему правило оказалось записано дважды: писали его в разные заходы и в разные дни, и во второй раз проверять, нет ли уже такого раздела, никто не стал. Способ, которым это нашлось, тоже обычный: подготовка вот этого слайда. Ревизию файла никто не затевал. Оба раза автор был уверен, что пишет впервые.
35 · Файл инструкций этого курса объявляет одно и то же правило дважды, с расходящимися деталями, и агент читает обе копии одновременно в каждой сессии¶
Это постоянная инструкция агенту — как вести работу, что считать готовым, чего не делать. Читается целиком при старте каждой сессии: не по разделам и не по нужде.
Правило, о котором речь, задаёт, какой длины обязана быть глава методички. Не короче тридцати тысяч слов. Вещь, которую агент обязан соблюдать, когда пишет.
Оно объявлено двумя разными разделами одного файла, и разделы расходятся. Первый — только про разбиение длинной главы на части. Второй добавляет, что засчитывается в объём, а что нет, и отменяет ориентир первого. Обе версии лежат в контексте одновременно, и команда на экране это показывает: она ищет заголовок по всему файлу и печатает номера строк, где он встретился. Встретился дважды — сто семнадцатая и четыреста семьдесят четвёртая.
Вторая строка — отдельный сорт. Правило, которое само про себя пишет, что перекрывает соседнее. Оговорку дописали руками, уже после того как конфликт сработал на живой лекции.
Третья строка — не находка, и в центр я её не ставлю. Шестьсот девяносто при пределе шестьсот бросается в глаза первым. Длина здесь ни при чём, и через два слайда мы это проверим.
Если спросят, почему не починили раньше: никто не приходил. Заметно ничего не ломалось, и оба раза, когда правило записывали, автор был уверен, что пишет его впервые.
Если спросят, что делает команда подробнее: она сверяет заданную строку с каждой строкой файла и печатает те, которые совпали, с их номерами. Ключ -n отвечает ровно за номера. На экране настоящий вывод, не пересказ: два совпадения — значит, заголовок в файле два раза.
Если спросят, в чём именно копии расходятся: первая говорит, что главу длиннее шестисот строк надо разбивать на части, и этим ограничивается. Вторая перечисляет, что в объём не входит — фронтматтер, оглавление, список источников, — и ставит собственный ориентир. Агент, прочитавший обе, не может сказать, считать ли оглавление.
Если спросят, почему это проблема, раз обе версии про одно и то же: потому что соблюсти можно только одну. Какую именно — решает порядок чтения и везение; само правило тут бессильно.
Если спросят, где ещё такое ищут: в любом файле, который правят много заходов подряд и который читают целиком, — сводка по стилю, перечень договорённостей команды, памятка по выкатке. Признак один и тот же: раздел дописывают, не проверив, нет ли уже такого. Повторите команду у себя на любом своём заголовке; если файл большой, два совпадения находятся с первого раза.
36 · Скилл — процедура, записанная отдельным файлом, которую агент открывает сам; грузится она тремя уровнями, и первый платится на каждом ходу независимо от вызова¶
Скилл — это процедура, записанная отдельным файлом. Агент открывает её сам, когда она понадобилась: вы не зовёте скилл руками и не вставляете его в запрос.
Грузится он тремя уровнями, и цена между ними различается качественно. Имя и описание — около ста токенов. Тело файла — до пяти тысяч, и только когда скилл выбран. Вложения — ноль, пока их не открыли.
Справа то, из-за чего «поставлю на всякий случай» обходится дороже, чем кажется. Дешёвым выглядит скилл, который лежит и ждёт; платите вы за него ровно столько же, сколько за рабочий. Первый уровень платится на каждом ходу, вызовется скилл или нет. А третий не платится вовсе, пока не открыт, и практического предела по объёму у него нет.
Выписка внизу — дословная цитата документации: перечень прибавляется к контексту на каждом ходу, и условий не оговорено никаких.
Если спросят, почему я назвал цитату дословной: формулировка в документации прямая и не оговаривает ни одного условия — читать её надо буквально, «на каждом ходу» значит на каждом, без оговорки «когда скилл понадобился».
Если спросят, сколько это в сумме: десять установленных скиллов — около тысячи токенов в каждом ходу, при том что вызовете вы за сессию один или ни одного. Сто токенов поодиночке незаметны; счёт идёт по числу скиллов и по числу ходов сразу.
Если спросят, почему тело не грузится заранее: потому что оно раз в пятьдесят тяжелее описания. Пять тысяч токенов на каждый скилл в каждом ходу — это цена, которую никто не станет платить за процедуру, нужную раз в неделю.
Если спросят, что считается вложением: любой файл рядом со скиллом. Обычный читается, когда тело на него сослалось. Скрипт запускается, и в контекст попадает только то, что он напечатал, — поэтому скрипт на сто мегабайт данных стоит столько же, сколько строчка его вывода.
Если спросят, где скиллы лежат: каталог внутри проекта, и имя каталога есть имя скилла. Устройство разберём на карте через несколько слайдов.
Если спросят, можно ли позвать скилл вручную: можно, по имени через косую черту. Способов вызова два, и разберём их на карте устройства; у ручного есть собственное неприятное свойство, на котором стоит пятый кейс.
Если спросят, чем это отличается от файла инструкций: файл инструкций читается целиком и всегда. Скилл читается по нужде. На этой разнице и стоит кейс, к которому мы идём.
37 · Выбор из пяти действий: что делать с файлом инструкций, в котором одно правило объявлено дважды и копии разошлись¶
Пять действий, и все пять настоящие: каждое из них с этим файлом кто-нибудь делал. Выберите любое — и скажите, почему именно этот ход при четырёх соседних.
Пауза. Три-четыре голоса, записываю без оценки.
И сразу честно: одно из этих слов звучало пять минут назад, я сам его произнёс. Поэтому узнать его — ещё не ответ: мне нужно, чем ваш ход отличается от каждого из четырёх соседних. Отдельно жду голосов за сокращение: карточка соблазнительная, и разбор адресован ей.
Если спросят, можно ли выбрать два действия сразу: можно, и это ближе всего к верному ответу. Тогда спрашиваю про порядок — какое из двух первым и почему.
Если прозвучит «свести копии»: это называют почти всегда, и это верно наполовину. Принимаю, не оценивая, и жду, скажет ли кто-нибудь вторую половину.
Если прозвучит «сократить до шестисот»: тоже принимаю молча. Это карточка, ради которой разбор существует, и опровергает её замер, и только он.
Если прозвучит «дописать, какая копия главная»: это не выдуманный неверный вариант — именно так в этом файле и сделано, строка двести шестнадцать. Говорю это на разборе, не здесь.
Если прозвучит «оставить как есть»: спрашиваю, из чего видно, что ничего не ломается. Ответа у этого варианта нет, и зал слышит это сам.
Если прозвучит что-то шестое — «спросить агента, какую копию он выбрал», «вынести оба правила в разные файлы», «переписать так, чтобы они не спорили»: беру и записываю наравне с карточками. Любой из этих ходов ложится в разбор, потому что разбор идёт по свойствам вариантов; готового списка ответов в нём нет.
Если никто не называет вынос: не подсказываю. Разбор идёт следующим слайдом и проходит по всем пяти.
38 · Все пять действий где-то правильные, у каждого названы случаи и ограничения; из сочетания следует порядок — сначала одна правда, потом её место, и вынос считается сделанным только после зачистки¶
Разбираю все пять. У каждого названы случаи и ограничения — из двух колонок вывод складывается сам.
Свести копии. Правильный ход, когда правило нужно почти всегда и остаётся в файле инструкций. Ограничение: молчит о том, где процедуре жить. Через три месяца рядом напишут третью версию — я так и получил вторую.
Вынести в скилл. Работает, когда тело большое, а нужно редко; когда две версии спорят и их надо развести; когда процедура исполняемая: скилл приносит её скриптом. Ограничения: имя и описание платятся в каждом ходу, и вынос без зачистки не считается.
Дописать приоритет. Не выдуманный неверный вариант, а то, что я сделал на самом деле: строка двести шестнадцать этого файла. Работает ровно один раз.
Сократить до шестисот. Соблазнительная карточка, и ради неё разбор существует. Шестьсот строк — мерка читаемости: сколько текста человек удержит в одном документе. Доведите до крайности: пусть файл был бы двести строк, а спор тот же. Убыток тот же, а мерка говорит «норма».
Оставить как есть. «Не ломается» никто не проверял, цена столкновения измерена.
Вывод. Первые две строки законны обе, и я говорю это прямо. Порядок: сначала одна правда, потом её место.
Если спросят, почему нельзя сразу вынести, без сведения: потому что выносить придётся одну из двух версий, а какая верна — ещё не решено. Вынесете неверную — получите скилл, который спорит с остатком в файле инструкций, и спор станет только труднее заметить.
Если спросят, зачем тогда вообще сводить, если вынос всё равно нужен: сведение — это решение о содержании, вынос — о месте. Их путают постоянно, и путаница дорогая: файл, в котором навели порядок, но ничего не вынесли, читается целиком по-прежнему.
Если спросят про цифры: величины с базами идут следующим слайдом, и там видно, что опровержение сокращения держится на замере. Здесь я сознательно говорю «проверено» и числа пока не называю: число без базы сравнения на слайде не стоит.
Если спросят, можно ли сочетать больше двух: можно, и в рабочем файле так и выходит. Свели, вынесли, зачистили, а приоритет дописали там, где развести не получилось. Оговорка остаётся законным инструментом рядом с решением; заменить решение она не может.
Если прозвучит «а если скилл окажется не нужен»: тогда платится имя и описание, и всё. Это и есть цена ошибки при выносе, и она маленькая — поэтому вынос прощает промах легче, чем кажется.
39 · Каждый шаг принятого решения подтверждён замером: цена спора измерена, опровержение сокращения — контролируемый эксперимент, а выигрыш загрузки по нужде растёт к концу сессии¶
Мы только что решили развести копии и вынести процедуру. Теперь — чего стоил этот спор и на чём держится каждый шаг.
Первая строка — цена спора. Два правила сталкиваются, соблюдаются оба сразу в 35,4% испытаний. То есть в двух случаях из трёх одно из них не соблюдено. Это наша сцена, посчитанная.
Вторая — почему сокращение отпало. Контролируемый эксперимент на четырёх характеристиках файла: размер, положение правила, устройство, наличие конфликта. Ни одна на соблюдение не влияет. На разборе я сказал «проверено напрямую» — вот этот замер, 1650 сессий.
Третья — почему вынос сильнее сведения в долгую. Считали буквально: агент пишет функцию за функцией, и с каждой следующей шансы соблюсти правило падают примерно на 5,6% против предыдущей. То, что лежало в контексте с самого начала, к концу сессии работает хуже всего.
Четвёртая — про вложения. Платить за объём не придётся, пока его не открыли. Поэтому крупное выносить не страшно.
Если спросят про 64,6%: это та же выборка, зеркальная величина, и столкновения в ней сконструированы специально. Как оценка «частоты нарушений вообще» она не годится, и авторы говорят это сами первыми. Я называю её только затем, чтобы никто не унёс её с занятия в этом качестве.
Если спросят, почему замеры идут после разбора, а не до: потому что иначе зал отвечает на вопрос, глядя на ответ. Цифра на пути к решению — это подсказка; цифра после решения — проверка. Второе полезнее и честнее.
Если спросят, как читать «не влияет статистически»: это значит, что в данных разницы не нашли. Утверждения, что её заведомо нет, замер не делает, и я его не делаю тоже. Для нашего решения достаточно и этого: ставку на сокращение замер не поддерживает ничем.
Если спросят, зачем тут четвёртая строка про вложения: она обслуживает предел применимости в конце кейса. Там вложение окажется правильным ответом для случая, в котором скилл уже не годится.
Если спросят, откуда взялись шесть наборов системных правил: это шесть опубликованных наборов инструкций от разных поставщиков, на них и ставили испытания. Пары конфликтующих правил собирали из них же, поэтому «спор двух правил» здесь означает ровно то, что у нас на сцене: две инструкции одного файла, которые нельзя соблюсти разом.
40 · Скилл целиком: каталог с одним обязательным файлом, три уровня загрузки, два способа вызова — и перечень, который решает всё до чтения¶
Карта на весь раздел. Дальше я буду называть эти слова, не объясняя их заново.
Первая часть. Скилл — каталог, и имя каталога есть имя скилла. Внутри обязателен ровно один файл. Фронтматтер — то, что между двумя тройками дефисов сверху: имя и описание. Тело — всё, что ниже, обычный текст по шагам. Вложение — файл рядом.
Вторая часть, и места ей отдано больше других. Три уровня, и разница между ними качественная. Имя и описание — всегда, с первого хода. Тело — только когда скилл выбран. Вложения — только если тело попросило.
Третья. Вызвать можно двумя способами: модель выбирает сама по описанию, или человек зовёт по имени через косую черту.
Четвёртая — перечень. По строке на скилл, и это всё, из чего делается выбор.
Пятая — тот же путь одной линией: запрос, перечень, выбор, тело, вложения.
Если спросят, что делает команда с косой чертой: открывает скилл с этим именем сразу, минуя выбор по описанию. Отсюда целый класс поломок: автор у себя всегда зовёт скилл вручную, поэтому негодного описания у себя никогда не увидит. У всех остальных скилл молча не выбирается.
Если спросят, почему описание пишут третьим лицом: оно ложится в системный промпт рядом с чужими описаниями. Разнобой в лице сбивает выбор: модель читает подряд десяток строк, и строка от первого лица выпадает из ряда. Так требует документация.
Если спросят, видно ли модели тело до выбора: нет. До выбора видно имя и описание, и больше ничего — ни тела, ни того, что скилл умеет на самом деле. Поэтому описание и решает всё.
Если спросят про скрипт во вложении: он запускается, и в контекст попадает только то, что он напечатал. Скрипт, перемалывающий сто мегабайт, стоит столько же, сколько строчка его вывода.
Если спросят, где среда ищет скиллы: в каталоге проекта и в личном каталоге пользователя. Оба перечня складываются, и в системный промпт уходят вместе — личный скилл виден модели в любом проекте, проектный достаётся всем, кто склонировал репозиторий.
Если спросят, сколько скиллов разумно держать: столько, сколько вы готовы оплачивать в каждом ходу. Счёт простой — около ста токенов на скилл, умножить на число ходов.
Если что-то непонятно — спрашивайте сейчас; дальше я буду на этот экран ссылаться.
41 · Процедуру вынесли в скилл правильно — и оставили её сокращённую копию в файле инструкций, где она читается в каждой сессии четыре с половиной месяца¶
Четыре вопроса к любому артефакту, и здесь на все четыре есть ответ на экране.
Где лежит: каталог .claude/skills, внутри — папка по имени скилла, внутри — файл SKILL.md. Что пишется: две строки фронтматтера, имя и описание. Какая структура: три дефиса, имя, описание, три дефиса, дальше обычный текст — сто шестьдесят пять строк. Как срабатывает: описание попадает в перечень, агент сам открывает файл, когда просят проверить деку.
Всё это сделано правильно, и сделано в мае.
А теперь вторая строка таблицы. Двадцать восемь строк той же процедуры остались в файле инструкций. Первый пункт этой копии — «вызови скилл pre-user-gate». То есть копия существует затем, чтобы отправить читателя в файл, который и так лежит рядом.
Считаем: двадцать восемь строк читаются при старте каждой сессии с семнадцатого мая. Четыре с половиной месяца. Платят дважды за одну процедуру — вот где убыток, и длина файла тут ни при чём.
Если спросят, почему так вышло: вынести приятно, вырезать страшно. Второй шаг делают гораздо реже первого, и никто не приходит сказать, что сломалось.
Если спросят, сколько это стоило в токенах: честного числа у меня нет. Двадцать восемь строк разметки — это порядка трёхсот-четырёхсот токенов на старте каждой сессии, но это прикидка по длине строки. Замером я её называть не буду. Что измерено точно — длительность и то, что платили всё это время.
Если спросят, чем копия отличалась от оригинала: она короче и успела отстать. Это второй сорт того же дефекта, который мы видели на сцене: две записи одной процедуры, написанные в разное время, расходятся молча.
Если спросят, как такое ловить: тем же способом, что и на сцене. Берёте заголовок вынесенной процедуры и ищете его по файлу инструкций. Если нашёлся — зачистка не доделана.
Если спросят, почему копию вообще оставили, а не вырезали сразу: потому что в момент выноса она казалась страховкой. Мысль была такая: вдруг агент не найдёт скилл по описанию — пусть в файле инструкций останется напоминание. Страховка сработала наоборот: напоминание грузится всегда, а скилл всё равно выбирается по описанию, и к выбору эта копия отношения не имеет.
Если спросят, что делать в этой ситуации по шагам: вырезать копию целиком, проверить, что описание скилла само по себе достаточно для выбора, и прогнать поиск заголовка ещё раз. Третий шаг обычно и пропускают.
42 · Прирост от скилла измерен на курированных — 33,9% против 50,5% на тех же задачах; среднее качество того, что лежит в открытых каталогах, вдвое ниже отобранного¶
Это провал решения, которое мы только что приняли сами. Чужой инструмент здесь ни при чём. Мы договорились, что процедуру стоит вынести, и ход этот верный. Теперь — что именно измерено под словом «помогает».
Первая строка: тридцать три и девять против пятидесяти с половиной процентов успешных прохождений. Плюс шестнадцать с половиной пунктов. База честная и сильная: те же восемьдесят семь задач, те же восемнадцать связок модели со средой, единственная переменная — есть курированный скилл или нет.
Ключевое слово — курированный. Замер поставлен на скиллах, которые кто-то прочитал, проверил и отобрал для этого эксперимента. Что бывает со случайным, измерено отдельно, и до этого мы дойдём в кейсе про чужой скилл. Здесь важно одно: шестнадцать пунктов обещаны тому скиллу, который прошёл отбор, и больше никому. Файл сам по себе прироста не даёт.
Если спросят про число задач: в пересказах встречается «84 задачи, 11 доменов». Это расхождение вторичных источников; в первоисточнике восемьдесят семь задач и восемь доменов, и называем мы только их.
Если спросят, что значит «связка модели со средой»: одна модель, запущенная в одной конкретной обстановке — свой набор инструментов, свой способ запуска. Восемнадцать таких связок и брали, чтобы результат не держался на одной модели.
Если спросят, кто отбирал скиллы для замера: авторы работы, и отбирали они сознательно, потому что им нужен был верхний край возможного. Поэтому цифра честно отвечает на вопрос «чего стоит хороший скилл» и молчит про средний.
Если спросят, что из этого следует практически: читать скилл перед установкой. Звучит скучно, и это единственное, что превращает чужой скилл в курированный. Отдельный кейс про это идёт в конце занятия, и там будет видно, что именно в чужом файле читать и в каком порядке.
Если спросят, относится ли это к нашему собственному выносу: относится напрямую. Процедуру, которую мы вынесли, писали мы сами и читали её глазами — она курированная по построению. Цифра говорит, что именно это свойство и оплачивается, а само по себе наличие файла не оплачивается ничем.
43 · Скилл окупается, когда тело большое, а срабатывает редко; за пределом — строка в файле инструкций, вложение или разговор про библиотеку целиком¶
Это предел применимости: вот докуда скилл окупается, а вот что берут дальше. Слева три случая, справа три замены — читается парами, по горизонтали.
Первая пара. Скилл окупается, когда тело большое, а срабатывает редко: сто токенов платятся постоянно, зато тело не грузится в тех сессиях, где оно не нужно. Переверните: процедура нужна каждую сессию — тело и так будет грузиться почти всегда, выигрыша нет, а шаг угадывания описания добавится. Такой процедуре место строкой в файле инструкций.
Вторая пара. Скилл хорош, когда содержимое читается целиком за один заход. Если объём огромен, а нужны из него куски — это вложение: ноль, пока не открыли, и практического предела по объёму нет. Тот самый третий уровень.
Третья пара — заявка на следующий разговор. Пока скиллов единицы и области не пересекаются, всё работает. Когда их десятки, ломается другое, и это отдельный кейс.
Нижняя строка — настоящий вопрос, и я жду на него ответа. Назовите процедуру из своей работы, и разложим её вслух.
Если спросят, что делать, когда процедура не попала ни в одну строку: называйте её, разберём. Обычно это процедура, у которой нет своего повторяющегося запуска — её делают раз в полгода и каждый раз заново вспоминают. У такой процедуры проблема не в месте хранения, и скилл ей не поможет.
Если прозвучит выкатка или разбор инцидента: это частые ответы у практикующих инженеров, и оба попадают в первую строку — тело большое, запускается редко. Раскладываю вслух: что в этой процедуре читают глазами, а что исполняют командой. Исполняемая часть уходит в скрипт рядом со скиллом, и в контекст попадает только то, что скрипт напечатал.
Если спросят, сколько скиллов считается «десятками»: точной границы работа не даёт, и я её не назову. Назову механику: каждый скилл платится именем и описанием в каждом ходу, и вместе с числом скиллов растёт вероятность, что модель выберет соседний. Обе величины растут, и ломается оно от их произведения.
Если спросят, можно ли держать процедуру и строкой, и скиллом сразу: можно, и ровно этим мы только что занимались на предыдущем слайде. Стоило это четырёх с половиной месяцев двойной оплаты.
Если спросят, зачем вообще знать предел, раз вынос нам сегодня подошёл: затем, что следующая процедура будет другой. Три строки слева — это проверка, которую делают до выноса; после него она уже ничего не меняет. Она занимает минуту и избавляет от правки, которую потом никто не доделывает.
44 · Тело скилла в контексте не лежит. До срабатывания модель видит одну строку — и по ней решает, открывать файл или нет¶
Два наблюдения, и оба знакомые. Файл написан хорошо, лежит на месте — а агент его не открывает. И зеркальное: открывается там, где не нужен, и платит контекстом в каждой второй сессии.
Общее у них одно. Решает это не содержимое. Тело скилла в контексте не лежит: до срабатывания модель видит одну строку. И по ней решает, открывать файл или нет. Весь кейс — про эту строку.
Если спросят, что будет дальше: перечень скиллов этой самой сессии, настоящий, снятый с машины, на которой сделано занятие. По нему и видно, что читает модель, когда выбирает. Тег наверху — три части описания и две длины, которые путают между собой; обе цифры прозвучат.
Если спросят, при чём тут предыдущий кейс: там файл инструкций спорил сам с собой, и починка была — вынести процедуру в отдельный скилл. Вынесли. Теперь выясняется, что вынести мало: вынесенное надо ещё уметь позвать, и зовёт его не человек.
Если спросят, почему кейс не про то, как писать скиллы целиком: тело мы собирали разделом раньше, и тело получается рабочее. Этот кейс про то, что между рабочим телом и сработавшим скиллом стоит ещё одна вещь — строка, которую видит модель.
Если спросят про счёт в теге: три части описания — что делает, когда звать, когда не звать. Две длины — предел самого поля и предел строки в перечне. Числа разные, путают их постоянно, и из этой путаницы растёт правило, которое отсюда стоит унести.
Если спросят, можно ли вообще обойтись без описания: можно, если звать скилл по имени руками. Тогда модель его не выбирает, и описание ей не нужно. Это отдельный режим, и к нему мы придём на пределе применимости, в конце кейса.
Если спросят, почему проблема сформулирована с двух сторон сразу: потому что чинятся они одним и тем же текстом и тянут его в разные стороны. Описание, которое ловит всё, открывается лишний раз; описание, которое ловит только своё, промахивается. Весь кейс — про эту пару.
45 · Двенадцать скиллов из тринадцати в этом репозитории показывают вместо описания собственное имя — а годное описание лежит строкой ниже и в перечень не попадает¶
Это перечень скиллов сессии, в которой сделано это занятие. Не пример и не макет — снимок с рабочей машины.
Читаем первую строку: build-deck: build-deck. Слева имя, справа описание, и они совпадают. Так же выглядят следующие шесть и ещё пять ниже. Выбивается одна — pre-user-gate: там написано, что скилл делает и когда его звать. Это единственный из тринадцати, у которого есть фронтматтер.
Теперь вторая карточка, и она важнее первой. Команда head -3 печатает первые три строки файла. Первая — заголовок. Третья — нормальное человеческое описание.
Содержание есть. Оно лежит на строку ниже того места, откуда среда берёт описание. Фронтматтера нет — описанием становится первая непустая строка, а это заголовок, который дублирует имя.
Проверить может любой: head -5 по всем файлам скиллов — она печатает первые пять строк каждого. Тринадцать выводов, двенадцать начинаются решёткой.
Если спросят, что такое фронтматтер: блок в самом начале файла между двумя строками из трёх дефисов, в формате «ключ: значение». Среда читает оттуда имя и описание. Нет блока — нечего читать, и описание берётся из первой строки текста.
Если спросят, почему авторы этого не заметили: потому что прямой вызов по имени работает и без фронтматтера. Набрал слэш, имя — скилл открылся. Ломается только автоматический выбор, а его отсутствие выглядит как «модель решила, что не нужно».
Если спросят, что делает звёздочка в .claude/skills/*/SKILL.md: оболочка подставляет вместо неё все имена каталогов внутри skills, и команда отрабатывает по каждому найденному файлу сразу.
Если спросят, почему это курс про себя: потому что проверяемо. Любой может склонировать репозиторий и повторить команду. Пример, который бьёт по автору, стоит дороже любого придуманного.
Если спросят, сколько это стоило: ничего и всё сразу. Скиллы работали — их звали руками. Автоматически за всё время не открылся ни один, и узнали мы это, когда стали готовить этот кейс.
Если спросят, чинится ли это разом по всем тринадцати: да, механически — дописать каждому файлу фронтматтер с именем и описанием. Работа на полчаса. Трудная часть другая: какой текст туда класть. Ровно ей и занят остаток кейса.
46 · Описание вставляется в системный промпт, и выбор делается по нему; а когда перечень не помещается в бюджет, описания отнимают у наименее вызываемых скиллов¶
Слева — то, что нужно держать в голове весь кейс. В системный промпт уходят имя и описание, по ним и делается выбор. Тела файла там нет вовсе.
Справа — петля, замкнутая сама на себя. Бюджет перечня около процента окна. При переполнении среда отнимает описания, начиная с тех скиллов, которые вызывают реже всего: первым теряет текст тот, кто и так ни разу не сработал, — и дальше не сработает уже поэтому.
Две длины, и их путают. Поле описания — тысяча двадцать четыре знака. Строка перечня — тысяча пятьсот тридцать шесть, и обрезается у неё конец. Отсюда правило: ключевой случай — первым. Теряете вы хвост. Значит в хвост кладут то, без чего можно обойтись. То, ради чего скилл писали, стоит в начале. Правило простое, и его стоит унести отсюда целиком.
Если спросят про запас: нашей деке урезание не грозит — тринадцать скиллов, около тысячи трёхсот токенов против примерно двух тысяч бюджета. Порог далёк, знать надо механизм.
Если спросят, почему длины две и какая из них главная: они про разные вещи. Тысяча двадцать четыре — предел самого поля, его проверяет валидатор при записи файла. Тысяча пятьсот тридцать шесть — потолок на одну запись в перечне, и в неё входит описание вместе с полем «когда звать». Первая ограничивает, что вы можете написать; вторая — сколько из написанного модель увидит.
Если спросят, как узнать, что твоё описание урезали: напрямую никак, и это худшая часть. Предупреждения нет, в журнале следа нет. Видно только по поведению: скилл перестал открываться там, где открывался раньше.
Если спросят, как считается процент окна: от окна той модели, которая работает в сессии. Окно больше — бюджет перечня больше. Поэтому один и тот же каталог на одной модели помещается целиком, а на другой начинает терять хвосты.
Если спросят, что именно считается «вызывается реже всего»: среда ведёт свой счёт срабатываний. Деталей она не публикует, и полагаться на этот порядок я бы не стал — закладываться надо на то, что урезание вообще возможно.
Если спросят, считать ли знаки руками: не нужно. Практическое правило — держать описание в пределах двух-трёх строк и ставить ключевой случай первым. В эти пределы уложится любое описание, которое человек вообще способен прочесть.
47 · Выбор из пяти описаний одного и того же настоящего скилла: какое из них сработает, когда надо, и промолчит, когда не надо¶
Пять редакций одной и той же строки. Это настоящий build-deck — тот самый, который минуту назад висел в перечне как имя-дубль.
Проверок две, и обе обязательны. Попросили «пересобери деку лекции» — скилл должен открыться сам, без имени и без слэша. Попросили «поправь опечатку в заголовке слайда» — открыться не должен, потому что делать ему там нечего, а контекст он съест.
Выберите строку, которая пройдёт обе. Не ту, которая красивее, а ту, которая проходит обе.
Пауза. Три-четыре голоса, фиксирую без оценки.
Если спросят, можно ли брать несколько: можно, и это полезный ответ — скажите, какие и чем они отличаются между собой.
Если выберут первую, «Собирает презентацию»: самый частый довод — «коротко и по делу, модель поймёт». Понять-то поймёт, а совпасть ей не с чем: просят словами «дека» и «слайды», и ни одного из них в строке нет.
Если выберут вторую, «Собирает деку из deck.yaml и slides»: довод обычно «названы конкретные файлы, промахнуться негде». Первую проверку она и правда проходит. Вторую — нет, и это надо вытащить вопросом: а если попросят поправить опечатку в слайде, что сделает скилл?
Если выберут третью, с «используй, когда просят пересобрать деку»: довод — «сказано, когда звать, этого достаточно». Почти достаточно. Спросите, что в ней сказано про случай, когда звать не надо.
Если выберут пятую, набор ключевых слов: довод — «модель ищет по словам, значит дадим ей слова». Это самое частое инженерное заблуждение из пяти, и ждать его стоит отдельно. Модель читает смысл описания; совпадения слов ей недостаточно.
Если спросят, почему все пять про один скилл: чтобы разница была только в тексте описания. Файл, тело, имя — одни и те же.
Если никто не назовёт четвёртую: это нормальный исход, и разбор от него не ломается. «Когда НЕ звать» почти никогда не приходит залу само — на том и стоит кейс.
48 · Обе проверки проходит только редакция из трёх частей: что делает, когда звать и когда не звать — последняя и удерживает скилл от лишнего срабатывания¶
Разбираем по колонкам, и колонки отвечают на разные вопросы. Средняя — где эта редакция права; правая — где она промахивается. Выбор выводится из пары колонок, сверху его не объявляют.
Первая карточка. Права она там, где слово «презентация» и есть рабочее: в проекте, где так просят. У нас просят «дека» и «слайды», ни одного из них в строке нет. Скилл промолчит там, где нужен.
Вторая. Предмет назван словами запроса, и первую проверку она проходит. Ограничение — «поправь опечатку в слайде» тоже про слайды. Откроется там, где не нужен, и будет открываться постоянно.
Третья. Назван не только предмет, но и повод — шаг вперёд. И она законна: в проекте, где спутать скилл не с чем, её достаточно. Ограничение — запрет не сказан, значит не действует.
Четвёртая. Повод назван и соседний случай отсечён. Разница с третьей ровно в одном обороте: «но не для правки одного слайда».
Пятая. Набор слов работает как подсказка человеку. Модель выбирает по смыслу написанного, и без глагола не сказано, что скилл делает.
Отсюда и состав: что делает, когда звать, когда не звать. Длина ни при чём — третья длиннее целевой и всё равно промахивается.
Если спросят, почему третья и четвёртая не равны, раз обе законны: они равны ровно до того момента, пока рядом не появился второй скилл про слайды. У нас он есть. Как только сосед появился, разделить их может только текст, и третья этого не делает.
Если спросят, почему первое лицо запрещено: описание адресовано модели, и она читает его как сведения о скилле. Обращения к себе она в нём не ищет. Дословные примеры «как не надо» из документации: Helps with documents, Processes data, Does stuff with files.
Если спросят, что делать, когда соседний скилл описан похоже: текстом это уже не чинится, и об этом будет предел применимости в конце кейса. Короткий ответ: либо развести области, либо выключить автоматический выбор флагом.
Если спросят, проверяет ли кто-нибудь описание автоматически: длину — да, валидатор при записи. Смысл — никто. Обе проверки, которые мы сейчас прогнали, делаются руками и голосом.
Если выбирали по длине: поставьте третью и четвёртую рядом и прочтите вслух. Третья длиннее, и она проваливается. Решает состав, и длина про него ничего не сообщает.
Если спросят, сколько всего таких описаний в репозитории курса: тринадцать, и двенадцать из них описания не имеют вовсе — это мы только что видели в перечне. То есть разбор не умозрительный: по этой же таблице предстоит переписать двенадцать настоящих строк.
49 · Два наивных фронтматтера ломаются каждый по своей причине; третий собирает зал — по одному предложению на каждый из трёх вопросов¶
Два наивных варианта на экране целиком, разбираем быстро.
Первый: фронтматтера нет, описанием становится заголовок — то, что мы видели в перечне двенадцать раз. Прямой вызов через слэш при этом работает, поэтому автор и не узнаёт, что автоматически скилл не откроется никогда.
Второй: описание есть, но общее. «Помогает с деплоем» — буквальный перевод формулировки, которую документация приводит примером «как не надо». Поле не пустое, файл годный, и ровно поэтому дефект незаметен.
Третья строка — та, которую мы сейчас соберём. Чем третий вариант обязан отличаться от второго?
Жду ответ. «Сказать, когда звать» приходит почти всегда.
Дальше три вопроса, по одному ответу на каждый. Что этот скилл делает. По каким словам его будут звать. И где он сработать не должен.
Записываю словами зала, своих формулировок не подставляю.
Если спросят, почему именно три вопроса: потому что три части описания, и каждая отвечает на свой. Первое предложение — что делает, третьим лицом. Второе — по каким словам звать. Третье — явное «не для…». Разобранная минуту назад таблица дала этот состав.
Если третья часть не приходит: это нормальный и ожидаемый исход. «Когда НЕ звать» почти никогда не называют сами — и это тот самый пропуск, из которого растёт лишнее срабатывание в каждой второй сессии.
Если спросят, что за скилл мы пишем: deploy для демо-репозитория signup-landing, каталог .claude/skills/deploy/. На дереве он помечен «по плану, коммита пока нет» — пишем мы его сейчас и по-настоящему.
Если спросят про запрещённые формулировки дословно: Helps with documents, Processes data, Does stuff with files. Все три устроены одинаково — глагол плюс расплывчатое существительное. «Помогает с деплоем» — их точный перевод, и попал он сюда не случайно.
Если спросят, почему прямой вызов работает без фронтматтера: потому что по имени каталог находится и так. Фронтматтер нужен только тому, кто выбирает сам, — модели.
Если спросят, обязателен ли порядок частей: порядок именно такой, и причина у него механическая. Перечень обрезают с конца. Значит, первым идёт то, без чего скилл не позовут вовсе, — что он делает; последним то, что потерять дешевле.
50 · Три ответа зала складываются в одно поле: что делает — третьим лицом, по каким словам звать, и где сработать не должен¶
Вот что получилось из трёх ответов. Первое предложение — что делает, третьим лицом. Второе — по каким словам звать, и слова настоящие: задеплоить, выкатить, опубликовать. И явное «не для обычных правок кода без деплоя».
Сверяем с тем, что продиктовал зал. Если формулировки другие — берём их: важен состав, а слова ваши подойдут лучше моих.
Две проверки внизу. Первая очевидная. Вторая — та, которую почти всегда пропускают: просим поправить опечатку в вёрстке, и открыться скилл не должен. Если открылся, описание слишком широкое. И вы купили себе лишнее срабатывание в каждой второй сессии.
Обратите внимание: все три части на месте и ни одна не длинная. Тут около двухсот пятидесяти знаков при поле в тысячу двадцать четыре — запас есть, и тратить его на красивые обороты смысла нет.
Если спросят про три слова подряд: они не для полноты. Это три разных способа попросить одно и то же, и все три звучат в работе. Чем ближе слова к тем, которыми просят, тем увереннее попадание.
Если спросят, что считается «слишком широким»: описание, под которое подходит соседняя задача, которой скилл не занимается. Проверяется это вторым запросом — на глаз по тексту не решить. Прочитать своё описание и признать его узким легко — на то оно и своё.
Если зал предложил что-то вроде «помогает с деплоем», дословные примеры «как не надо» из документации: Helps with documents, Processes data, Does stuff with files. Все три устроены одинаково — глагол плюс расплывчатое существительное.
Если спросят, когда правка станет видна: в существующем каталоге — сразу; если каталог только что создан, нужен /reload-skills, он перечитывает каталог скиллов заново.
Если спросят, не слишком ли длинное получилось описание: оно укладывается в оба предела с запасом — тут около двухсот пятидесяти знаков при поле в тысячу двадцать четыре. Запас есть, и тратить его на красивые обороты смысла нет.
Если спросят, почему «не для обычных правок кода» сформулировано так широко: потому что отсекать надо класс задач целиком, одного примера мало. Перечислить все правки кода нельзя, а назвать их классом — можно.
Если спросят, нужно ли перечислять все синонимы подряд: нет, и места на это не хватит. Трёх-четырёх настоящих слов достаточно; придуманные синонимы, которых никто не произносит, только съедают знаки.
51 · Тело без литеральных команд задачу не решает — оно её переносит: угадывание переезжает из файла инструкций внутрь скилла¶
Описание решает, откроется ли файл. Тело решает, что произойдёт после.
Наивный вариант коварнее, чем кажется: текст годный, скилл сработает, и поэтому дефект незаметен. Не сказано одного — какой именно командой. Модель угадает заново, и задача угадывания остаётся на месте и переезжает внутрь скилла, где её труднее заметить.
Нижняя карточка — пять шагов с пустыми местами. Назовите команду на каждом. Четвёртый и пятый шаг команд не имеют: они исполняются руками.
Иду по шагам, спрашиваю на каждом: какой командой?
Если на четвёртом и пятом шаге начнут придумывать команду: её нет, они исполняются руками, и выдумывать незачем — на слайде её тоже нет.
Если спросят, почему нельзя написать «собрать проект» и положиться на модель: потому что в репозитории способов сборки обычно несколько — старый скрипт, новый, и ещё один в документации. Модель выберет любой из них, и выберет заново в каждой сессии. Скилл пишут ровно для того, чтобы выбор был сделан один раз.
Если спросят, не устареет ли литеральная команда: устареет, и это честная цена. Зато устаревание видно: команда падает, и её чинят. Угаданная команда не падает — она просто иногда делает не то.
Если спросят, откуда взяты сами команды: из демо-репозитория signup-landing, того самого, с которым мы работаем всё занятие. Это не иллюстрация — это его настоящий порядок выкатки.
Если спросят, что делать с шагами, у которых команды нет: оставлять словами и говорить это вслух. Пятый шаг — запись в журнал задач; он ручной, и притворяться, что его можно автоматизировать, не нужно.
Если спросят, сколько шагов нормально: столько, сколько в процедуре, но каждый — проверяемый. Шаг, про который нельзя сказать, выполнен он или нет, в теле скилла бесполезен.
Если спросят, чем это отличается от обычного скрипта: тем, что скилл читает модель, а оболочка его не исполняет. Скрипт выполняется целиком и молча; тело скилла — это инструкция агенту, который может остановиться на середине, увидеть красный тест и доложить. Литеральные команды нужны обоим, а решение «идти дальше или нет» есть только у второго.
52 · Пять шагов, у каждого названо действие целиком: три литеральные команды и два шага, которые исполняются руками¶
Сверяем с тем, что назвал зал. Каждый шаг называет действие целиком, до команды.
Разберём три команды, они не всем одинаково знакомы. npm run build запускает сборку, описанную в самом проекте: превращает исходники в готовые файлы сайта и складывает их в каталог dist. Код выхода ноль означает, что сборка дошла до конца.
npx playwright test открывает сайт в настоящем браузере и проходит форму так, как прошёл бы человек. Зелёным называют прогон, где ни одна проверка не упала.
wrangler pages deploy dist выкладывает содержимое каталога на хостинг. Дальше ловушка: имя проекта в конце. Почти всегда его забывают, а без него команда публикует не туда.
Честная арифметика: шагов пять, литеральных команд три. Четвёртый и пятый исполняются руками. Придумывать им команду незачем — на слайде её нет.
И правило с другой стороны, про соблазн быть полным: не предлагать несколько способов без необходимости. Ровно один — тот, что в этом репозитории действительно работает.
Если спросят, что такое npx: запускает программу, не устанавливая её в проект насовсем. Берёт нужную версию на время прогона и после себя не оставляет ничего.
Если спросят, почему код выхода назван прямо в тексте шага: потому что «собралось» и «команда завершилась» — разные события. Сборка умеет падать и печатать при этом много обнадёживающего текста. Код выхода — то, что проверяется однозначно.
Если спросят, обязателен ли именно wrangler: нет, он привязан к нашему хостингу. У вас будет своя команда выкатки, и правило от этого не меняется: одна команда, названная целиком, вместе с тем параметром, который указывает цель.
Если спросят, почему ручные шаги вообще оставлены в скилле: потому что они часть процедуры. Скилл — это записанный порядок; набором команд он не исчерпывается. Шаг, который делают руками, пропускают ровно тогда, когда он нигде не записан.
Если спросят, не устареют ли команды: устареют, и чинить их придётся. Зато устаревшая команда падает заметно, а угаданная моделью — не падает, она просто иногда делает не то.
Если спросят, что лежит в .tasks/active/: журнал выполненных задач репозитория, обычные файлы с датой в имени. Пятый шаг пишет туда строку о выкатке. Нужен он ради следующего раза: когда через месяц понадобится узнать, что именно выложено на прод, ответ будет лежать в репозитории, и спрашивать ни у кого не придётся.
53 · Сфокусированный скилл обгоняет исчерпывающий набор на той же выборке задач — интуиция «раз пишу, напишу полным» измеримо проигрывает¶
Провал бьёт по решению, которое мы приняли минуту назад: описание написали правильно, и дальше рука тянется написать тело полным.
Измерение против этого прямое: сфокусированный скилл обгоняет крупные и исчерпывающие наборы. База — та же выборка из восьмидесяти семи задач, менялась только структура самого скилла.
Почему так — вторая строка. Откроется файл или нет, решает описание. Объём тела на выбор не влияет никак: до срабатывания тела в контексте нет вовсе. Раздувая тело, вы удорожаете каждое срабатывание и не улучшаете ни одного выбора. Плата без покупки.
Рекомендация ровно про это: держать файл до пятисот строк, подробности выносить в отдельные файлы — те самые вложения, которые стоят ноль, пока не открыты.
И честно: направление подтверждено первоисточником, числа разрыва в работе нет. Процента здесь не стоит, и придумывать я его не буду.
Если спросят, что такое «сфокусированный» и сколько это: в работе сказано «максимум три модуля», но что такое модуль скилла, она не определяет — файл, раздел, вложение? Поэтому число я не называю. Границу мы провели своим правилом: до пятисот строк, остальное во вложения.
Если спросят, почему верят направлению без числа: потому что у него есть механизм, который мы только что разобрали, и он объясняет результат независимо от размера эффекта. Число сказало бы, насколько выгодно; механизм говорит, почему выгодно вообще.
Если спросят, что такое вложение: отдельный файл рядом со скиллом, на который тело ссылается. Модель открывает его, только если дошла до соответствующего шага. Пока не открыла — он не стоит ничего.
Если спросят, как понять, что тело раздуто: по числу случаев, которые оно пытается покрыть. Если в одном скилле и выкатка, и откат, и настройка окружения — это три скилла, у каждого своё описание и свой повод.
Если спросят, не противоречит ли это предыдущему слайду, где мы расписывали шаги подробно: нет. Подробность шага и объём тела — разные вещи. Пять точных шагов короче двадцати приблизительных.
Если спросят, откуда взялись восемьдесят семь задач: это публичная выборка, на которой меряли скиллы. Важно в ней то, что выборка одна и та же в обоих прогонах — менялась только структура скилла, а задачи оставались прежние. Без этого сравнение не значило бы ничего.
54 · Одного описания хватает, пока спутать скилл не с чем и зовут его теми же словами; дальше решает уже не текст описания¶
Предел у этого кейса есть, и проходит он там, где описание перестаёт быть тем, что решает.
Первая строка — обычный случай: скиллов единицы, спутать не с чем, описание работает.
Вторая — то, что чинится дописыванием. Зовут другими словами, чем вы написали. Добавляйте настоящие слова запроса; абзац объяснения здесь не поможет, перечень всё равно обрежет конец.
Третья строка снимает ложную безальтернативность, и её обычно не знают. Автовыбор можно просто выключить: флаг disable-model-invocation со значением «истина». Скилл остаётся, позвать его по имени можно, а модель его описание не видит — выбрать не может ни правильно, ни ошибочно. Для процедуры, которую нельзя запускать по догадке, это честнее любого описания.
Теперь вопрос внизу, и он настоящий. Назовите скилл, который вы бы модели выбирать не дали.
Короткая пауза. Беру один пример и иду дальше.
Если спросят, что считается «похожим описанием у соседа»: такое, под которое подходит один и тот же запрос. Точное совпадение имён разрешает приоритет уровней — проект выигрывает у пользователя. Похожий смысл не разрешает ничто: модель молча берёт один из двух, и записи об этом нет нигде.
Если названный пример окажется про необратимое действие — выкатку, миграцию, удаление данных: это и есть правильный ответ, и стоит сказать вслух, почему. Цена ошибочного срабатывания там несимметрична: лишний запуск сборки стоит минуту, лишний запуск миграции стоит вечер.
Если спросят, не проще ли всегда ставить этот флаг: нет. Со всеми флагами каталог скиллов превращается в набор команд, которые надо помнить наизусть, и автоматический выбор пропадает там, где он полезен. Флаг ставят точечно, под конкретный риск.
Если спросят, видно ли в сессии, что флаг стоит: описание такого скилла в перечень не попадает. Проверяется тем же head -5, которым мы начинали кейс: фронтматтер на месте, а в перечне строки нет.
Если спросят, что делать с двумя своими похожими скиллами прямо сейчас: свести их в один с общим описанием и развести шагами внутри тела. Разделять текстом два близких описания — работа, которая не кончается.
55 · Задача стоит сегодня, готовое чужое решение на неё уже есть, а своё — это недели работы: решаем, что в этом случае делать¶
Шестая развилка, и она первая за занятие, где вы ничего не писали сами. Задача заказчика стоит сегодня. На неё уже есть чужой скилл, выложенный в открытый каталог, и ставится он за минуту. Своё решение той же задачи — недели работы, и это ещё оптимистичная оценка. Решаем, что в этом случае делать.
Тег наверху: один официальный скилл, четыре замера, три условия отказа.
Если спросят, зачем эта развилка отдельно от предыдущей: предыдущие пять были про то, что вы пишете и ставите сами, и там ответственность за содержимое ваша по построению. Здесь содержимое чужое, и это другой вопрос. Прежний был «как написать»; этот — «что принять». Поэтому развилка отдельная, и поэтому она последняя: к ней нужны все пять предыдущих.
Если спросят, про какую задачу речь: разбор PDF заказчика — текст, таблицы, заполненные формы. Это следующий слайд, и там названо, почему готовое выигрывает честно по трём меркам из четырёх.
Если спросят, чем кейс кончится: тем, при каких условиях чужой скилл — верное решение. Не предупреждением, а условиями, и все три проверяются до установки. Это я говорю сразу, чтобы развилка не читалась как подводка к запрету: отказ здесь такой же законный исход, как установка, и у него будет своя строка в разборе наравне с остальными.
Если спросят, относится ли это к хукам: относится, и в конце кейса будет сказано, как именно. Чужой хук приезжает с клоном репозитория, а решения об установке никто не принимает.
Если кто-то уже знает ответ и называет его вслух — принимаю и не разворачиваю. Разбор идёт через четыре слайда, и до него расклад должен остаться открытым.
56 · Задача решается готовым скиллом сегодня или своим за недели; и качество готового при этом честно выше¶
Сцена не про наш репозиторий и не про наши тринадцать скиллов — это был вопрос прошлого кейса. Здесь вы не написали ничего: вы решаете, брать ли чужое.
Задача настоящая и обычная: разобрать PDF заказчика — текст, таблицы, заполненные формы. Официальный скилл ровно на это существует, и его описание документация приводит как образец того, каким описание должно быть.
На схеме четыре мерки. По первым двум — срок и качество разбора таблиц — готовое выигрывает честно, и это надо проговорить без иронии. Свой разбор таблиц в PDF — недели, и выйдет он хуже. Оговорюсь сразу: «недели» — я оцениваю объём работы на глаз.
Третья мерка про поддержку, и она двусмысленная: чужую поддержку вы получаете бесплатно, пока проект жив, и теряете вместе с ним.
Четвёртая — «что внутри». Здесь выигрывает своё, и весь кейс держится на ней. Вы не знаете, что внутри.
И последнее, про момент. Никто не стоит перед выбором «безопасно или опасно». Выбор звучит как «сегодня или через месяц» — поэтому его и делают за минуту.
Если спросят, какой это скилл: официальный скилл разбора PDF из документации Agent Skills. Его описание там приведено дословно: извлекает текст и таблицы из PDF, заполняет формы, объединяет документы. Мы будем возвращаться к этой строке на разборе описаний.
Если спросят, откуда «недели»: это моя оценка, и она построена на одном — разбор таблиц в PDF не решается библиотекой за вечер, потому что таблица в PDF не размечена как таблица — её восстанавливают по координатам текста. Замера у меня нет, и выдавать оценку за замер я не буду.
Если спросят, почему чужая поддержка — не плюс целиком: потому что она кончается без предупреждения. Автор перестал вести проект — вы остались с каталогом, который больше никто не правит, и с форматом заказчика, который менять продолжают.
Если спросят, нельзя ли просто прочитать чужой скилл и успокоиться: можно прочитать, и это правильный ход. Он отвечает на вопрос про сегодняшнее содержимое и ничего не говорит о завтрашнем. До этого дойдём на провале.
Если спросят, при чём здесь качество разбора таблиц: это единственная мерка, где превосходство готового измеримо и проверяемо на ваших же файлах. Остальные три либо про срок, либо про знание.
57 · Вместе со скиллом приходит каталог с исполняемым кодом, который запускается с правами вашей сессии, а разрешение вы даёте один раз¶
Слева — что физически приезжает: каталог, а в нём текст, вложения и скрипты. Тело, вложения и, если автор захотел, скрипты.
Состав каталога вы уже видели на карте скиллов, и я его не пересказываю. Добавляю к нему два свойства, которых на той карте не было. Первое: скрипты идут через оболочку с вашими правами, не с урезанными. Второе — справа.
Справа то, что упускают почти все. Соглашаетесь один раз, права остаются. Содержимое потом может поменяться, и второй раз не спросят.
То есть вы одобряете не код, который выполнится, а каталог.
Если спросят, что значит «с правами вашей сессии»: ровно то, что скрипт может сделать всё, что в этот момент можете вы. Прочитать любой файл, до которого дотягивается ваш пользователь, записать в него, сходить в сеть, прочитать переменные окружения — включая те, где лежат ключи. Отдельной урезанной учётной записи у скилла нет.
Если спросят, спрашивают ли разрешение на запуск скрипта: на первый — да, и это то самое разовое согласие. Дальше работает уже выданное.
Если спросят, как содержимое меняется после установки: обычным обновлением. Автор выложил новую версию, она приехала, вы её не читали. Для вас это выглядит как «ничего не произошло», и в этом вся трудность.
Если спросят, не защищает ли от этого сам каталог скиллов: нет. Каталог раздаёт файлы, а что в них — ответственность того, кто ставит. Это прямая позиция производителя, и на провале я приведу её дословно.
Если спросят, почему вложения тоже считаются: потому что тело на них ссылается, и они приедут в контекст тогда, когда тело сошлётся. Читать их надо наравне со скриптами.
Если спросят, чем это отличается от обычной библиотеки, которую ставят из пакетного менеджера: размером площади и тем, кто решает. Библиотеку вы подключаете в коде и вызываете там, где написали вызов. Скилл выбирает модель, по описанию, в тот момент, когда сочтёт подходящим, — и вы этот момент не назначали.
58 · Выбор из пяти карточек: что делаете с готовым чужим скиллом, который объективно лучше вашего будущего¶
Пять карточек. Выбирайте.
Пауза. Три-четыре голоса, фиксирую без оценки.
Ещё раз расклад, если нужно. Готовый скилл делает нужное лучше, чем сделаете вы, и ставится за минуту. Вместе с ним приезжает каталог с кодом, который исполнится с вашими правами. Задача заказчика при этом стоит сегодня, и месяца на неё нет. Карточек пять, и выбрать можно любую. Что делаете?
Жду, не назовёт ли кто-нибудь два действия вместо одного.
Если спросят, можно ли выбрать две карточки сразу: можно, и это ответ сильнее одиночного. Скажу об этом только после того, как соберу голоса.
Если зал назовёт «взять как есть»: принимаю без возражения и спрашиваю, что считается проверкой. Обычно отвечают «посмотреть описание» или «посмотреть, кто автор» — и это две разные вещи, из которых ни одна не смотрит на то, что исполняется. Разбор на следующем слайде показывает, во что это обходится.
Если зал назовёт «вычитать и взять»: спрашиваю, что именно вычитывать и в каком порядке. Порядок здесь и есть содержание ответа, и почти никогда его не называют сразу.
Если зал назовёт «взять с выключенным автовызовом»: хороший ход, и спрашиваю, от чего он защищает. Он закрывает срабатывание не вовремя и ничего не говорит про содержимое.
Если зал назовёт «написать своё»: спрашиваю, сколько это займёт и что получится. Обычно тут же сами и отвечают, что дольше и хуже.
Если зал назовёт «не ставить вовсе»: это законный ответ, и я его не оцениваю. Спрашиваю, при каком условии он верен, — условия в разборе есть, и их три.
Если никто не поднимет пятую карточку: называю её сам одной фразой и иду дальше. Она понадобится на разборе, и там у неё своя строка наравне с остальными.
59 · Сначала вычитать то, что исполняется, потом ставить; для необратимого — ставить с выключенным автовызовом. «Не ставить» тоже имеет свою область¶
Пять строк, три колонки. Смотрим, где каждый вариант работает и чем ограничен, а решение собираем из сочетания.
Первая — «взять как есть». Возражение на неё — измерение, и оно без страшилок: из ста двадцати пяти разобранных случаев функционального вреда восемьдесят шесть дали скиллы, которые выглядели подходящими задаче.
Вторая строка. Вычитка работает, когда предмет общий, готовое уже лежит и есть кому прочитать скрипты до установки. Ограничение честное: это снимок на сегодня. И внутри неё уточнение, ради которого эта строка здесь и стоит: читают не все подряд, читают то, что исполняется.
Третья — выключенный автовызов. Закрывает момент вызова, про содержимое молчит. Там, где действие необратимо, она обязательна.
Четвёртая — написать своё. Работает, когда предмет ваш. Для общей задачи это недели и результат хуже.
Пятая, и на ней остановитесь. Отказ — законный исход, и у него три условия: некому вычитать, скрипт лезет наружу, цена ошибки необратима. Хватает одного.
Строка вывода внизу: вторая и третья не спорят, они складываются. Сначала вычитать, потом ставить; для необратимого — с выключенным автовызовом.
Если спросят, почему вторая и третья не считаются одним ответом: потому что они закрывают разные дыры. Выключенный автовызов отвечает на «сработает тогда, когда не звали». Вычитка отвечает на «внутри лежит чужой исполняемый код». Выключив автовызов, вы не узнали про содержимое ничего; вычитав, не назначили момент вызова.
Если спросят, сколько времени занимает вычитка: на скилл с одним скриптом в сотню строк — минут пятнадцать, если искать четыре конкретные вещи и не разбирать код целиком. Что искать — на следующем слайде.
Если спросят, откуда восемьдесят шесть: это 68,8% от ста двадцати пяти функциональных провалов в работе, где один и тот же прогон делали со скиллом и без него, на тех же задачах. База сравнения поэтому прямая.
Если спросят, что делать, когда условие отказа одно, а задача горит: тогда решение принимает не инженер. Это тот случай, когда называют цену вслух и отдают выбор тому, кто отвечает за последствия.
Если спросят, не проще ли всегда писать своё: нет, и это тоже измерено. Прирост от готового реален, и отказ от него оплачивается неделями работы и худшим результатом.
Если спросят, как выключают автовызов: строкой disable-model-invocation: true во фронтматтере скилла — она запрещает модели открывать его по своему усмотрению, и остаётся только вызов по имени, который делает человек. Мы разбирали её в кейсе про описание.
Если спросят, годится ли «вычитал один раз и забыл»: нет, и провал через слайд ровно об этом. Обновление чужого скилла — это новая установка, и читать его надо так же, как читали первый раз.
60 · Под каждым шагом разбора лежит свой замер: прирост измерен у отобранного скилла, средний из открытых каталогов вдвое хуже по той же рубрике, а четверть из них несёт уязвимость¶
Мы только что решили: сначала вычитать то, что исполняется, потом ставить. Вот под чем это решение стоит.
Две таблицы, и это две разные работы. Верхняя смотрела на качество, нижняя — на уязвимости. Корпуса у них разные, и это видно по шапкам.
Верхняя, первая строка, помечена «уже видели»: тот самый замер из кейса про повод. Там он говорил, что помогает отобранный; здесь обосновывает шаг «брать».
Вторая строка верхней — поворот. Прирост дал скилл, который кто-то прочитал и отобрал. Средний из каталогов по той же двенадцатибалльной рубрике набирает шесть с небольшим против десяти. Отсюда шаг «отбирать».
Нижняя таблица — размер риска. Четверть скиллов несёт уязвимость, пять процентов — признаки умысла. Точность и полноту детектора называю сразу: без них проценты не читаются.
Последняя строка самая практичная. Скиллы со скриптом внутри уязвимы вдвое чаще. Отсюда и порядок чтения: скрипты первыми.
Если спросят, почему корпуса не сходятся: потому что это две независимые работы с разными выборками. Сорок семь тысяч смотрели на качество по рубрике, тридцать одна тысяча — на уязвимости детектором. Они и не должны сходиться, и складывать их нельзя.
Если спросят, что такое верхний квартиль: четверть корпуса с лучшими баллами по той же рубрике. Отобранные для замера скиллы брали оттуда, и десять и одна десятая — их средний балл.
Если спросят про точность и полноту детектора: точность — какая доля найденного действительно уязвима, полнота — какую долю настоящих уязвимостей он нашёл. Восемьдесят шесть и восемьдесят два процента соответственно. То есть двадцать шестой процент — оценка снизу.
Если спросят, есть ли вторая пара чисел по уязвимостям: есть, и она заметно выше. Методика другая, и складывать их нельзя, поэтому называем одну пару и её источник.
Если спросят, почему двенадцать баллов: это рубрика самой работы, двенадцать пунктов по структуре и содержанию скилла. Шкала чужая, и своей я её не заменяю.
Если спросят, где взять отобранный: отбор делаете вы сами, читая скилл перед установкой. Знака качества, который можно спросить у каталога, сегодня нет ни в одном из двух корпусов.
Если спросят, что считается признаком злого умысла: обращение наружу, которого задача не требует, — выгрузка файлов, скрытая загрузка кода, чтение ключей. Детектор искал именно их, и это те же четыре вещи, которые мы будем искать глазами на следующем слайде.
61 · Вычитка чужого скилла — четыре места в определённом порядке; машина из них проверяет одно, и вот что она при этом печатает¶
Порядок здесь обратный тому, который просится, и в этом вся польза слайда.
Просится начать с тела: там же написано, что скилл делает. Начинать надо со скриптов. Тело — это текст, и модель может ему не последовать. Скрипт выполнится обязательно, и с вашими правами. Плюс измерение из свидетельств: со скриптом внутри уязвимость вдвое вероятнее.
Что искать в скриптах — вторая таблица, первая строка. Обращения наружу: сеть, переменные окружения, ключи, запись за пределы каталога проекта. Понимать код целиком не нужно, нужно найти эти четыре вещи.
Вложения — то же самое плюс ссылки за пределы каталога скилла. Фронтматтер третьим, и здесь смотрят на ширину описания: слишком общее заставит скилл срабатывать там, где вы его не звали. Тело — последним.
И внизу единственная машинная проверка. Команда claude plugin validate читает каталог и говорит, что в нём сломано, не запуская сессию. Вот её живой вывод на скилле с испорченным фронтматтером. Обратите внимание на вторую половину сообщения: при запуске такой скилл загрузится с пустыми полями, и молча.
Если спросят, что именно сломано в этом примере: в значении description осталась незакрытая квадратная скобка. Разбор YAML на ней падает, и весь фронтматтер уходит пустым.
Если спросят, что проверка НЕ ловит: всё остальное. Она не читает скрипты, не оценивает ширину описания, не смотрит, что делает тело. Это проверка читаемости файла. Безопасность скилла она не проверяет.
Если спросят про код возврата: ошибка — единица, значит команду можно ставить в сборку. Если нашлись только предупреждения, возврат нулевой; флаг --strict делает предупреждения ошибками, и тогда возврат снова единица.
Если спросят, почему «каталог с манифестом»: команда проверяет плагин или витрину, то есть каталог, внутри которого лежит .claude-plugin с описанием. Чужие скиллы обычно так и приезжают — плагином из витрины. Если вам дали голый каталог скилла, проверка скажет «манифест не найден» и ничего не проверит.
Если спросят, есть ли то же самое вне Claude Code: есть. Формат скиллов — открытый стандарт, и у него своя проверялка, skills-ref validate, из эталонной библиотеки стандарта. Сам claude plugin validate вендорский.
Если спросят, сколько это занимает: скилл с одним скриптом на сотню строк — минут пятнадцать, пока ищешь четыре названные вещи и не вчитываешься в остальное.
Если спросят, что делать, когда скрипт обфусцирован или просто нечитаем: это и есть ответ. Нечитаемый скрипт — условие отказа, и разбирать его дальше дороже, чем обойтись без скилла.
62 · Официальный скилл производителя переделали так, что он тихо запускал шифровальщика; а в одном каталоге за одиннадцать дней число вредоносных выросло с 341 до 824¶
Провал бьёт по решению, которое мы только что приняли: вычитали и взяли.
Первый случай — самый неудобный из возможных, потому что скилл официальный. Конвертер картинок, открытый, от самого производителя. Внутрь добавили одну функцию, которая тихо скачивает и запускает шифровальщика. Снаружи ничего не поменялось: имя, описание, поведение — те же. Исследователи раскрыли находку производителю; ответ был, что ответственность за запускаемые скиллы лежит на пользователе.
Честно про силу: это воспроизведённый пример, доказывающий возможность. Насколько часто так делают в дикой природе — не измерено, и я этого не утверждаю.
Второе — измерено. Один открытый каталог, сплошной обход: триста сорок один вредоносный из двух с лишним тысяч. Через одиннадцать дней тот же обход: восемьсот двадцать четыре из десяти тысяч семисот.
Обратите внимание, что я считаю вслух. Каталог вырос почти вчетверо, вредоносных стало вдвое больше. Доля при этом снизилась: двенадцать процентов против восьми. Пугать вас ускорением было бы нечестно.
И вывод, ради которого провал стоит здесь. Вычитка — снимок на сегодня, про завтрашнее содержимое она молчит. Значит обновление чужого скилла — это новая установка.
Если спросят, почему производитель не закрыл дыру: потому что закрывать нечего в смысле ошибки в коде. Скилл устроен так, что исполняет то, что в нём написано, с правами того, кто его поставил. Это свойство механизма, и позиция производителя такая: выбирать и запускать доверенные скиллы — задача пользователя.
Если спросят, что такое MedusaLocker: семейство программ-шифровальщиков, известное с две тысячи девятнадцатого года. В этом примере его не писали заново — его просто скачивали и запускали из служебной функции скилла.
Если спросят, как вообще заметить такую вставку: по тому самому порядку чтения с прошлого слайда. Функция, которая лезет в сеть и запускает скачанное, видна в скриптах, даже если не разбирать логику целиком.
Если спросят, почему доля упала, а я всё равно считаю это плохой новостью: потому что абсолютное число удвоилось за одиннадцать дней, и попадётся вам конкретный файл, и доля на нём ничего не решает. Доля отвечает на вопрос «ухудшается ли экосистема»; ответ — нет, растёт вместе с собой.
Если спросят, относится ли это к официальным каталогам: первый случай именно про официальный открытый скилл. Происхождение от производителя защищает от случайного мусора и не защищает от того, что файл кто-то изменил по дороге к вам.
63 · Чужой скилл — правильный выбор, когда предмет общий, есть кому вычитать исполняемое и действие обратимо; за пределом берут своё или не берут вовсе¶
Кейс кончается тем, когда чужое правильно. Левая плашка и есть ответ: три условия, и все три проверяются до установки. Предмет общий, исполняемое есть кому вычитать, действие обратимо. Если все три есть — берите; это лучшее доступное решение.
Справа — что делают, когда условие не выполнено. Вторая строка самая частая: некому вычитать.
Четвёртая строка про масштаб. Когда скиллов набирается десятками, мешать начинает сама библиотека: на тех же задачах при росте до двухсот двух падение успешности доходит до двадцати одного процента, и падает точность выбора. Двести два — крайняя точка измерения; где начинается, работа не говорит, и порог я придумывать не буду.
Последние две строки — про то же самое в других местах, и на них стоит задержаться. Хук мы хвалили за то, что он приезжает с клоном без установки. Это же свойство значит: вместе с чужим репозиторием приезжает чужое исполняемое, и запускается оно с вашими правами. Скилл вы ставите решением, а хук получаете вместе с git clone, не приняв никакого решения.
Вторая: скилл переносится копированием каталога на любого агента, который читает этот формат. Риск переезжает тем же копированием.
Если спросят, что считать «общим предметом»: то, что одинаково выглядит у вас и у чужой команды. Разбор формата, работа с документами, типовое преобразование. Как только в задаче появляется ваш регламент или ваш формат — предмет перестал быть общим.
Если спросят, кто может быть «тем, кто вычитает»: любой, кто читает код и понимает, что такое обращение наружу. Это не роль безопасника, это пятнадцать минут внимательного чтения по списку с прошлого слайда.
Если спросят, как отличить обратимое действие от необратимого: по тому, есть ли шаг назад без потерь. Сборка, прогон тестов, генерация файла — обратимы. Выкатка, миграция схемы, удаление, отправка наружу — нет.
Если спросят про двести два скилла: это крайняя точка измерения в работе. Промежуточных порогов там нет, и сказать «после сорока начинается» я не могу — такого числа в работе не измеряли.
Если спросят, какие поля ломают переносимость: те, что Claude Code принимает сверх стандарта, — выключение автовызова, подсказка аргументов, выбор модели. Скилл с ними работает здесь и перестаёт быть переносимым; при выгрузке лишнее поле даёт прямую ошибку.
Если спросят, где именно другой агент ищет скиллы: каталоги у всех свои, и это единственное, что при переносе меняется. Сам файл не трогают.
Если спросят, что делать, когда условий больше одного и они конфликтуют: смотреть на правую колонку. Невыполненное условие всегда ведёт в один из двух исходов — своё или ничего, и третьего здесь нет.
64 · Наш барьер ветки переносится на другой агент решениями целиком: переписываются объявление и форма ответа, а там, где механизма нет вовсе, решение держит слой надёжнее исходного¶
Вопрос, который вы зададите в понедельник: всё это привязано к одному инструменту? Берём наш барьер ветки и кладём на другие агенты.
Cursor читает наш файл настроек сам — правок ноль. Codex и Copilot: переложить файл, тело скрипта не трогать. Все пять решений на месте.
Gemini. Переписать объявление, около шести строк. И ловушка. Срок ожидания там задаётся в миллисекундах. Наша десятка перенесётся синтаксически безупречно и станет десятью миллисекундами — барьер будет молча отваливаться по сроку, то есть пропускать. Тот же отказ, который мы разбирали на третьем кейсе, только добытый переносом; автор здесь ничего не напутал.
Windsurf. Отвечать можно только кодом выхода. Состояния «спросить» нет вовсе — а это одно из наших пяти решений, и выразить его там нечем.
Aider. Механизма нет совсем — ни хука, ни доступа наружу, ни субагента, трёх ступеней из пяти. И это ответ сильнее остальных: решение остаётся, держит его защита ветки на площадке — слой надёжнее исходного.
Последняя строка — про источник. Это проверено по документации, запуском — нет, и так я это и говорю.
Справка.
Если спросят, проверяли ли вы это руками. Нет, и это написано на слайде. Проверка по документации поставщиков и текстам спецификаций, первое октября, семнадцать первоисточников. Самое тонкое место — Cursor: его документация не описывает, какой вход получает перенесённый хук, и «правок нет» выведено из описания его собственного события. Проверяется одной сессией; этой сессии мы не провели.
Если спросят, что переносится совсем без правок. Тело скрипта. Поле tool_input.command, из которого наш jq достаёт команду, называется одинаково у Claude Code, Cursor, Codex, Copilot и Gemini. У Windsurf оно называется иначе — там правка есть и в теле.
Если спросят, чем держать правило у Aider. Тремя способами, и у каждого своя цена. Хук самого git в служебном каталоге — работает и против человека, но с клоном не едет; эту развилку мы разбирали. Защита ветки на площадке — срабатывает, даже когда барьер промолчал. Проверка ветки внутри тестовой команды — слабее, срабатывает уже после правки.
Если спросят, значит ли это, что перенос дешёвый. Смотря что переносить. Приём есть у всех семи агентов, которых я смотрел, а у одного из семи нет трёх механизмов из пяти — ни хука, ни доступа наружу, ни субагента; скилл и процесс у него работают. Договорённости о записи хука нет ни у кого: три поставщика читают наш формат, но обещания совместимости не даёт ни один из трёх.
Если спросят, зачем это занятию. Затем, что пять решений вы принимали сами, и ни одно из них не принадлежит инструменту. Переносится решение; переписывается запись решения.
65 · Две строки оси закрыты — хук и скилл, у каждой названо, чего от неё ждали и что вышло на деле; MCP, субагент и процесс остаются пустыми до следующего занятия¶
Вторая строка легла в таблицу. Усиления здесь те же пять и в том же порядке, что в начале занятия; тогда у каждого стояла одна строка — что это такое. Теперь у двух из них стоит замер.
Хук. Заводим его, когда правило уже нарушено. Устройство обещает: поставили хук — и коммит в главную ветку закрыт. Проверка показала другое. Из шести форм одной и той же команды барьер отклоняет одну, на пяти молчит. База здесь обязательна: пять форм молчания ничего не значат, пока не сказано, что всего их шесть. И человека, который печатает ту же команду в своём терминале, барьер не видит.
Скилл. Заводим по сигналу — когда файл инструкций перерос сам себя. Устройство обещает, что решает содержание, а описание можно дописать позже. Проверка показала, что выбор идёт по описанию: без точного триггера файл не загрузится ни разу, каким бы хорошим он ни был внутри.
И последнее, про все пять сразу. Переносится решение — что считать нарушением, когда вмешиваться, что вынести отдельным файлом, какие права урезать. Не переносится запись: имя события, папка, форма ответа «нет», единицы срока. А механизма может не быть вовсе: решение тогда в силе, держит его уровень надёжнее.
Три нижние строки пустые не потому, что про них нечего сказать. Мы до них просто не дошли — их заполнит следующее занятие.
Справка.
Откуда шесть форм. Самотест барьера на ветке seminar-5-hook, коммит 9803643: девять проверок проходит, пять упираются в предел, ни одна не падает. Шесть форм — это шесть способов записать одну и ту же команду коммита, которые разбирались на ступени хука. Запускается он одной командой из репозитория, и печатает он это сам.
Если спросят, значит ли это, что хук бесполезен. Нет. Он закрывает тот способ, которым агент действительно пишет в главную ветку, и закрывает надёжно. Остальные пять — цена, которую надо знать заранее, до того как она обнаружится в проекте.
Если спросят про колонку «что обещает устройство». Это не чья-то наивность. Так механизм описан в документации и так он выглядит, пока его не замерили. Разница между этой колонкой и соседней — и есть то, ради чего мы весь час мерили.
Если спросят, почему строк пять, а закрыто две. Пять усилений названы в начале, и названы честно: сегодняшнее занятие берёт два. MCP, субагент и процесс — следующее; доступ наружу уехал туда решением владельца курса целиком.
Если спросят, у каких ступеней запись договорились делать одинаково. У скилла и у доступа наружу: формат опубликован, владелец у протокола нейтральный, и один и тот же файл читают десятки инструментов. У хука и субагента такого договора нет — приём есть у всех, а записывается он у каждого по-своему.
Если спросят, где посмотреть замеры. Репозиторий публичный, ветка и коммит на предыдущих слайдах. Самотест клонируется и запускается, таблица в нём совпадает с тем, что в этой колонке.
Остаток себе. Пустые слоты не комментирую дольше одной фразы: занятие кончается на том, что проверено, и три незакрытые строки — часть этого результата. Извиняться за них я не буду.
66 · Две ступени добавили в репозиторий два файла, подтверждённых коммитом, и один по плану без коммита — граница между «написано» и «уже работает» показана на слайде, а не спрятана¶
На входе в занятие каталога .claude/ здесь не было. Посмотрите, что в нём теперь лежит — и на метки справа, они важнее самого дерева.
Коммит подтвердил две строки: файл настроек и самотест хука. Номер коммита на слайде, адрес репозитория тоже. Склонируйте и запустите самотест — он сам напечатает, на чём барьер молчит.
Третья строка — файл скилла. Он по плану, коммита у него пока нет, и метка стоит прямо на слайде. Занятие было про разницу между «файл лежит» и «механизм срабатывает»; прятать эту разницу в собственном итоге было бы странно.
Файл инструкций подрос с двадцати четырёх строк до сорока. Новый раздел здесь один, и дал его хук: описание механизма и того, кого он не останавливает. Правило про ветки лежало в файле ещё на входе — с него и начался первый кейс; хук дописал к нему третий пункт, про переключение ветки отдельной командой.
«Написано, что будет» — это ещё не «уже работает».
Справка.
Что делают команды, которыми это проверяется. git clone <адрес> забирает репозиторий целиком. git checkout seminar-5-hook переключает рабочую копию на ту ветку, где лежат обе подтверждённые строки, — в главной ветке их нет. git log -1 печатает последний коммит; его номер должен совпасть с тем, что на слайде. Запуск самотеста — одна команда из корня репозитория, и печатает он таблицу проверок сам.
Если спросят, почему скилл без коммита. Потому что его файл написан в плане ступени, а в репозиторий ещё не внесён. Выдавать это за сделанное нет оснований, поэтому на слайде стоит метка. Это тот же критерий, которым мы весь час мерили механизмы.
Если спросят, почему разделов стало пять, а добавили один. Было четыре: три от прошлого занятия и репозиторный этикет, с которого мы начинали первую развилку. Хук добавил пятый — описание барьера. Четыре плюс один — пять; рост файла — с двадцати четырёх строк до сорока, то есть шестнадцать строк, проверяется счётом строк.
Если спросят, зачем правило текстом, раз есть барьер. Барьер останавливает агента в момент вызова. Текст объясняет человеку, который откроет репозиторий, почему вызов остановлен и кого барьер не останавливает вовсе. Один работает, другой читается.
Если спросят про ветку. Работа ступени велась в отдельной ветке намеренно: в главную её вливают после проверки, и именно это правило барьер и охраняет.
67 · Тот же вопрос открытия и те же пять карточек — второй раз за занятие; зал отвечает снова, и вслух называется, у кого ответ изменился и что именно его изменило¶
Час назад этот вопрос уже звучал, и свой ответ вы держали при себе. Карточки те же пять и в том же порядке: ни одна из них за час не стала правильной.
Вопрос тот же, знак в знак, и карточек столько же. Изменилось за этот час только одно: под двумя из пяти теперь лежит файл, который можно открыть.
Сначала руки: у кого ответ изменился. Потом два-три голоса — что именно его изменило. Свой ответ не называю, чужие не оцениваю.
Справка.
Что обычно меняет ответ, и что на каждое отвечать. Чаще всего уходят от хука — после того, как барьер при них показал, на скольких формах команды он молчит. Это движение честное, и я его подтверждаю: механизм закрывает один путь, класс остаётся открытым. Второе частое — приходят к процессу: раз механизм надо ещё и проверить, нужен порядок, в котором проверка записана. Тоже принимаю. Третье — остаются на хуке с оговоркой «но с узким матчером»; это тот вывод, к которому вела ступень, и я называю его вслух.
Если ответ сдвинулся к скиллу. Спрашиваю, какой сигнал они у себя видят. Если файл инструкций разросся — сигнал настоящий, и это правильный ответ для их проекта.
Если зал молчит. Напоминаю, что появилось за час: два файла в репозитории и две заполненные строки. Больше не подсказываю: здесь работает пауза.
Если прозвучит «а какой ответ правильный». Отвечаю, что его нет и сегодня: выбор зависит от того, какой сигнал в проекте уже прозвучал. Полный разбор всех пяти — в конце следующего занятия, когда будут закрыты оставшиеся три.
Чего здесь не делаю. Итог не подвожу — он на следующем слайде. Ничего сделать после занятия не прошу. Чей ответ «вырос», не оцениваю.
68 · Под двумя карточками из пяти теперь лежит файл, который можно открыть и проверить командой; под тремя остальными такого файла нет — их ступени впереди¶
Посмотрите, где строки заполнены, а где стоят пустые слоты. Разница между ними и есть итог часа.
Хук. Барьер стоит, и свои дыры он печатает сам: девять проверок проходит, пять форм молчания называет собственным голосом. Открыть можно файл настроек и самотест — ветка и коммит на слайде.
Скилл. Судьбу процедуры решает её описание, и лежит оно во фронтматтере файла: видно, не открывая тело.
Под тремя нижними строками нет ни файла, ни команды, ни сигнала. Их ступени просто впереди. Если кто-то минуту назад передвинул туда свой ответ — фиксирую и не опровергаю: проверить его сегодня нечем, и с этой неопределённостью занятие заканчивается.
Закрываю так. В рабочем репозитории у многих из вас барьер уже стоит, и стоит он с широким матчером — просто это пока ничем не проверено. Эти же две колонки к нему и применяются.
Справка.
Что делают команды, которыми проверяется каждая из двух строк. У хука — запуск самотеста из корня репозитория: он печатает таблицу проверок, где у каждой проверки стоит исход, и пять строк с пределом видны в ней прямо. У скилла — чтение фронтматтера файла процедуры: описание и имя лежат там в первых строках, тело при этом не читается вовсе. Обе проверки занимают минуту и не требуют ничего, кроме склонированного репозитория.
Если спросят, почему строк именно две, а не три. Доступ наружу решением владельца курса уехал на следующее занятие целиком. Заявить третью строку и не проверить её значило бы сделать ровно то, против чего построен весь час.
Если спросят, что считать результатом занятия. Не два файла. Результат — то, что про каждый из них можно задать проверяемый вопрос и получить ответ командой. Файл, про который такого вопроса не задать, в этой таблице не стоит.
Если спросят, что делать дальше. Отвечаю словами, без задания: следующее занятие берёт оставшиеся три ступени и закрывает их тем же способом.
Если прозвучит «а у нас хук уже есть». Этот случай встречается чаще прочих. Спрашиваю, на скольких формах команды он молчит, — и обычно ответа нет, потому что никто не мерил. Вот этот вопрос и стоит унести.
Остаток себе. Призыва что-либо сделать не даю: занятие кончается на том, что стало проверяемым.



































































