lint → eval → стенд; что измерено
В статье:
Три уровня, от дешёвого к дорогому. Первые два — в CI на каждый PR, третий —
на стенде по расписанию. Уровень выше не заменяет уровень ниже: lint ловит
форму, eval — выбор, стенд — правду.
bxshef lint --dir <навыки> --code <исходники> проверяет каждый навык по
STANDARD.md. С --code каждый класс вида \Vendor\Ns\Class
из текста навыка должен объявляться в коде (совпадение по namespace или по
суффиксу); корни, которых в коде нет (Bitrix\*), не проверяются; примерные
вендоры — --ignore '*\Demo\*,Acme\*'. Навыки, которые ссылаются на несколько
модулей, проверяются против общего каталога с их checkout'ами — маски
--ignore по namespace ненадёжны.
Не тест кода — тест описания: модель получает имена и описания всех
навыков набора и по фразе выбирает один. Промах — вина 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 соседа. Без них
рост числа навыков ухудшает выбор молча.Что отладили за три прогона и что нужно повторять дословно.
Два каталога. Решатель (ИИ-агент) работает в отдельном каталоге без
.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 ложных.
Каждая строка стала правилом в STANDARD.md. Это и есть способ, которым стандарт растёт: не из соображений, а из провалов на стенде.
Образ коробки Битрикс24 (лицензия) — стенд только на своём Docker или
self-hosted раннере. Задачи TASKS.example.md привязаны к модулям shef.*;
для другой библиотеки их пишут заново по тому же шаблону: фраза дословно,
ожидаемый навык, чек-лист с доказательствами.