Методология проверки

lint → eval → стенд; что измерено

Три уровня, от дешёвого к дорогому. Первые два — в CI на каждый PR, третий — на стенде по расписанию. Уровень выше не заменяет уровень ниже: lint ловит форму, eval — выбор, стенд — правду.

уровеньчто проверяетинструментцена
1. lintfrontmatter, длина описания, evals у операционных, противоречия в evals, привязка к вендору, классы против кодаbxshef lint [--code]0, секунды
2. evalпо фразе задачи модель выбирает нужный навык из всех описанийbxshef eval (любая OpenAI-совместимая модель; по умолчанию BitrixGPT через AI Router, бесплатно) и --agent claude (настоящий Claude Code)0 / токены, минуты
3. стендИИ-агент с навыками решает реальную задачу, результат ставится на портал, чек-лист по фактуstand/bx.php, claude -p, задачи из TASKSчас стенда, токены

Уровень 1 — lint

bxshef lint --dir <навыки> --code <исходники> проверяет каждый навык по STANDARD.md. С --code каждый класс вида \Vendor\Ns\Class из текста навыка должен объявляться в коде (совпадение по namespace или по суффиксу); корни, которых в коде нет (Bitrix\*), не проверяются; примерные вендоры — --ignore '*\Demo\*,Acme\*'. Навыки, которые ссылаются на несколько модулей, проверяются против общего каталога с их checkout'ами — маски --ignore по namespace ненадёжны.

Уровень 2 — eval

Не тест кода — тест описания: модель получает имена и описания всех навыков набора и по фразе выбирает один. Промах — вина description, править его, а не порог.

  • --repeat 3 --min 0.9 — выбор стохастичен; одиночный прогон давал 9/9 и 7/9 на одних описаниях. Три повтора и порог 0.9 — рабочая настройка для CI.
  • --only реальная — только фразы с пометкой из настоящих задач; они важнее придуманных.
  • --agent claude — настоящий Claude Code во временном каталоге с навыками, без записи и сети; считается первый вызов Skill в первых N ходах. Гонять по расписанию, не на каждый PR: медленно (~30 мин на 9 фраз × 3).
  • expected может быть массивом: если на фразу верны два навыка, метрика не должна считать второй промахом.
  • При объединении наборов разных модулей в один каталог первым делом добавить перекрёстные фразы: фразу соседа с expected соседа. Без них рост числа навыков ухудшает выбор молча.

Уровень 3 — стенд

Что отладили за три прогона и что нужно повторять дословно.

Два каталога. Решатель (ИИ-агент) работает в отдельном каталоге без .git, без evals, без отчётов — только local/, навыки и исходники библиотеки, на которую опирается задача (в реальном проекте они всегда рядом, и агент может их прочитать). Исполнитель прогона держит результаты в другом каталоге. Прогон 1 провалился именно на этом: решатель читал чек-листы.

Решатель без хостовых настроек. claude -p с --setting-sources project --strict-mcp-config, запрет сети и docker через --disallowedTools, --permission-mode acceptEdits, --output-format stream-json в файл — из него потом видно, какой навык взят и каким по счёту действием.

Отзыв — единственная сеть решателя. Навык отзыва шлёт тикет сам, curl-ом (feedback/README.md, «Подключить навыки»). Стенд поднимает свой приёмник (cd feedback && make build-local — 127.0.0.1:8787, токен чтения dev), в копии навыка отзыва в каталоге решателя меняет боевой адрес на http://127.0.0.1:8787/feedback и разрешает решателю ровно этот вызов: --allowedTools 'Bash(curl -sS -m 30 -X POST http://127.0.0.1:8787/feedback:*)'. Остальная сеть закрыта, как раньше; в боевой приёмник стенд не пишет.

Режим A/B. Одна и та же фраза без навыков и с навыками; счёт — число правок до приёмки и пункты чек-листа. Режим A измеряется один раз, дальше только B против прошлого B.

Порядок одной задачи: reset → footprint до (пусто) → сессия решателя → поставить результат на портал → install → footprint после (строки CORE-TOUCHED — красный флаг) → чек-лист → uninstall → footprint (остатки — дефект) → отзыв в приёмнике стенда: тикет с context.skill задачи, принятый после её начала (нет — дефект) → строка в results.csv.

Чек-лист — да/нет с доказательством одной строкой, общие пункты на каждую задачу: код в local/modules/<id>; установка не пишет вне local/ кроме разрешённого; после удаления нет остатков; отзыв есть. Образец — stand/TASKS.example.md. Отзывы стенда: curl -s -H 'Authorization: Bearer dev' 'http://127.0.0.1:8787/feedback?skill=<навык>'.

stand/bx.php — обвязка на портале: status, install, uninstall (печатает причину фатала), reset (только для тестовых модулей, без DoUninstall), footprint (файлы вне модуля, опции, агенты, события, UF), run-agent (печатает FATAL), options, uf, sql. Кладётся в /opt/www/tools/ контейнера, вызывается php bx.php <команда> <module_id>.

Что мерить: навык взят (да/нет, каким действием), пунктов чек-листа, правок до приёмки, отзыв оставлен, CORE-TOUCHED, остатки после удаления. Отдельно — угадывания: места, где агент придумал namespace или сигнатуру. Каждое угадывание — правило в навык (см. STANDARD п. 5).

Ревизия чужого модуля — отдельный сценарий: агенту дают модуль на базе библиотеки и просят список расхождений с каноном; исполнитель помечает каждое «подтверждаю по коду / не подтверждаю / не могу проверить». Показывает, видит ли агент канон или выдумывает. В прогоне 2: 6 из 6 подтверждены, 0 ложных.

Что измерено (сентябрь 2026, модули shef.*)

прогончто проверялирезультат
1A/B на 9 задачахнавык взят в 5 из 9; где взят — правок 60 → 20
1 → 2описания без привязки к вендорувыбор 9/9 настоящим агентом
2точные контракты вместо отсылокнечего угадывать → задачи 5/5
3повтор проблемных задач5/5 с 0 правок; найден дефект в самом модуле (_log() не объявлена), который не нашли ни тесты, ни ревьюеры

Каждая строка стала правилом в STANDARD.md. Это и есть способ, которым стандарт растёт: не из соображений, а из провалов на стенде.

Что не публикуется

Образ коробки Битрикс24 (лицензия) — стенд только на своём Docker или self-hosted раннере. Задачи TASKS.example.md привязаны к модулям shef.*; для другой библиотеки их пишут заново по тому же шаблону: фраза дословно, ожидаемый навык, чек-лист с доказательствами.

Источник: skills-standard/METHOD.md — правки туда, сайт пересобирается сам.
CtrlI