Repository navigation
Releases
v0.19.0
Выпуск про одно: «поставил» не значит «работает» — и AQK теперь говорит, что поставить.
aqk adopt засчитывает проверку, только если она объявлена, краснеет на заведомом браке и идёт
в конвейере. doctor называет инструменты, которые подходят проекту и нигде не стоят, — словами
человека и с командой установки, — и показывает, какие правила .aqk/rules держит проверка, а
какие только человек. Про четырнадцать сторонних инструментов AQK знает, как каждый незаметно
выключают, — по их официальной документации, с дословной цитатой.
Что может выглядеть иначе после обновления. В doctor два новых блока: сводка по папке
правил («держит проверка — N, человек — M» и команды aqk add для обещанных, но не поставленных
проверок) и «Что ещё стоит поставить». Если npx не смог запустить инструмент (нет сети, нет
прав на кеш), гейт отвечает «не смогли проверить» (код 2), а не «находка». entry-commands-exist
в проекте на CMake или autotools пишет «цели make не проверены» вместо обвинения. Правила в
.aqk/rules несут пометки <!-- aqk: … -->; чтобы обновить уже разложенные копии, удалите папку
.aqk/rules и запустите aqk init — без --force, он перезаписывает и .aqk.yml.
Добавлено
doctorсоветует, что поставить, — словами человека. Блок «Что ещё стоит поставить»: до
трёх инструментов вне каталога, которые подходят репозиторию по его признакам и не стоят ни в
одной проверке, — что поймает, как поставить и как доказать (aqk adopt). Пример: «schemathesis —
есть описание API — расхождение API с его описанием…». Попутно найдено: у axe и k6 в условии стояли
признаки, которыхdoctorне вычисляет (has_frontend,has_server), — совет по ним не сработал
бы никогда; теперь это сторожит приёмкаunits-tools.mjs. Новый признакhas_gh_actions(zizmor
проверяет только GitHub Actions).- У каждого правила
.aqk/rulesназван сторож, иdoctorговорит, чего не хватает. 47 правил
размечены<!-- aqk: … -->: 12 держит запись каталога, 35 — человек.doctorпечатает сводку и
по каждой обещанной правилами проверке, которой нет в манифесте, — командуaqk add. Разметку
сторожитunits-rules.mjs: пометка обязана вести в существующую запись, русская и английская
копии — совпадать. Повод — замеры 2026 года: правило текстом агент соблюдает всё хуже с каждой
новой функцией, а файлы правил не поднимают долю решённых задач. - Две новые методички.
engineering-glossary.md— словарь понятий, которыми ставят задачу
агенту и проверяют его код (связанность, DRY, идемпотентность, N+1, законы Люссера, Гудхарта,
Конвея, Хайрама, рамки RED/USE/DORA, 29 признанных стандартов).agent-evaluation-2026-06.md—
исследования весны 2026 о подгонке под проверку: названия всех работ arXiv сверены заново, три
числа поправлены по аннотациям. - Гейт
private-names— закрытые проекты владельца не попадают в публичный репозиторий.
Сверяет каждое слово файлов с отпечатками SHA-256 запрещённых имён: самих имён в репозитории нет,
и в выводе слово не печатается. Сверка нашла 83 упоминания закрытого проекта в текущих файлах —
убраны; снимок его проверок (kit/docs/ai/quality-gates-checklist.md) удалён целиком. - JavaScript комплекта — под biome (гейт
biome,tool/selfcheck/biome.sh,biome.json).
Выбран замером наtool/: eslint с рекомендуемыми правилами — 50 замечаний, biome — 88, из них
43 про оформление; по сути оба нашли одно. biome — одна программа без пакетов в нашем
package.json. Правила оформления выключены, предупреждения считаются находками
(--error-on-warnings). Неиспользуемые импорты (9) и переменные (2) убраны сразу, остальные 36
замечаний — долг под храповиком. - Скрипты оболочки комплекта — под shellcheck (гейт
shellcheck,tool/selfcheck/shellcheck.sh).
Первый прогон: 88 замечаний. Две ошибки исправлены сразу, одна из них настоящая — в
research/corpus/handwritten-vs-generated.shhere-документ перебивал трубу, и скрипт насчитывал
ноль рукописных копий при любых данных (результат нигде не опубликован). Остальное — долг под
храповикомratchets/shellcheck.txt: новое замечание не пройдёт. Сведения о shellcheck — в
kit/tools/: порог-S errorпрячет предупреждения, в том числе подстановку без кавычек. - Поле манифеста
own_samples:— образцы проверок, написанных самим проектом.npm test,
make check, свои скрипты доказываются по<own_samples>/<имя>/red|green, отдельно от
каталога записей (samples:): там образец своей проверки читался бы как новая запись. Так же
принято снаружи — у semgrep тест правила лежит рядом с правилом. У самого AQK:checks/gates,
образцы для всех семи собственных прогонов и дляdead-code— все 31 гейт комплекта
доказаны. Свои образцы берутся раньше образцов каталога: запись бывает поставлена не тем
рецептом, под который написаны её образцы (у насdead-codeна knip, а образцы записи —
питоновские). - Доказательство подсадкой — только в
aqk proveиaqk adopt.doctor --run,badgeи
reportего пропускают и называют это: копия проекта и три прогона гейта втрое дороже самого
гейта (на AQK — 3 с → 22 с). В нашем конвейереproveидёт отдельным шагом заданияcheck, и
общее время от этого не растёт — его задаёт задание windows. proveдоказывает любую команду проекта, а не только команду из каталога. Раньше
npm run lint,make check,ruff checkсо своим конфигом назывались «недоказуемыми»:
подставить каталог образца было некуда. Теперь дерево красного образца кладётся по своим путям
в копию проекта, команда идёт как есть и обязана покраснеть; на зелёном — промолчать. Копия
сначала проверяется чистой: команда, красная без подсадки, называется отдельной причиной.
Рабочее дерево не меняется.aqk adopt <гейт>— договор установки: «поставил» не значит «работает». Код 0, только
если гейт объявлен, у него есть красный и зелёный образцы, он доказан на них и идёт в
конвейере. Для каждого непройденного шага — что именно сделать и куда положить. «Прочитать
официальную документацию» печатается шагом для агента и не засчитывается: машина его не
проверяет. Повод — замер того же дня: Stryker по умолчанию не роняет сборку никогда
(thresholds.break: null), и у 96 из 149 настоящих файлов его настроек на GitHub порога нет.
Сводка для агента теперь велитadoptпосле любой установки инструмента.- Сведения о сторонних инструментах —
kit/tools/: ruff, eslint, biome, knip, Stryker, jscpd, vulture, gitleaks, zizmor, mutmut, schemathesis, k6, axe.adoptопознаёт
инструмент по команде гейта (и по скриптуpackage.json, который она зовёт) и говорит, не
заглушён ли он:ruff --exit-zero,ruff check --fixбез--exit-non-zero-on-fix,ruff formatбез--check, eslint с правиламиwarnи без--max-warnings 0, eslint с
--no-error-on-unmatched-pattern; biome с правиламиwarnбез--error-on-warnings, правила
info(не роняют никогда),--no-errors-on-unmatched,--skip-parse-errors; knip с
--no-exit-codeили--max-issuesбольше нуля; Stryker безthresholds.break(задаётся только в
файле настроек — из команды его не передать) и сallowEmpty; jscpd с--exit-code 0и без
--fail-on-empty; vulture с--min-confidenceвыше 60 (прячет все неиспользуемые функции и
классы); gitleaks с--exit-code 0; zizmor с--no-exit-codes,--format=sarifи--fix.
mutmut не роняет проверку ни при каком числе выживших мутантов — документация об этом молчит,
установлено замером (mutmut 3.8.0:runиresultsвыходят с нулём), и правило помечено как
замер, а не цитата; в починке — обёртка, проверенная на том же проекте. schemathesis, сужённый
до--checks not_a_server_error; k6 безthresholdsв скрипте теста (скрипт читается по пути из
команды) и с--no-thresholds; axe без--exit.
Каждое правило — с дословной цитатой из официальной
документации и адресом; цитаты сверяет с исходникомtool/selfcheck/tools-quotes.mjs, примеры
каждого правила прогоняетunits-tools.mjs.
Изменено
- Пуш и выпуск быстрее, проверок столько же.
smoke.shзапускает свои две части — 113
проверок оболочки и 192 проверкиnode --test— одновременно, а не одну за другой: локально
98 → ≈70 с, счёт тот же, 305. Конвейер на Windows разложен на три параллельных задания
(каталог, две частиsmoke) вместо одного одиннадцатиминутного. Выпуск больше не повторяет
прогон гейтов, а требует зелёного конвейера на этом же коммите — то есть ещё и Windows с
образом, которых прежний шаг выпуска не смотрел.
Исправлено
checkwashподнят с 0.3.4 до 0.4.2 — в конвейере и локально. 0.3.4 объявлял «тест пропал»,
когда в файл тестов добавляли случаи в массив; в 0.4.2 этого нет, образцы записи
test-not-adjustedна новой версии доказаны заново (aqk adopt).entry-commands-existбольше не обвиняет проект на CMake. Если Makefile создаёт генератор
сборки (CMake, autotools), цели make называются «не проверены», а не «нет такой цели»; общее
правило%:(Makefile Sphinx) принимает любую цель; «make» в комментарии#внутри блока кода —
текст. Найдено при подготовке письма в чужой репозиторий: все четыре находки оказались ложными.aqk proveбольше не подписывает сбой проверки как «команда пустая»: это «НЕ СМОГЛИ доказать —
сбой самой проверки», жёлтым, с причиной и хвостом вывода — как и «красная без подсадки».- npm, не сумевший запустить инструмент, — «не смогли проверить», а не находка.
npx knip
без кеша (контейнер без домашнего каталога), без сети или с недоступным реестром выходит с кодом
1 — тем же, каким knip сообщает о мёртвом коде, и AQK объявлял исправный гейт сломанным.
Подпись собственной неудачи npm —npm error code E…(npm ERR! code E…у старых версий), кроме
ELIFECYCLE: так старый npm подписывает упавший скрипт, то есть находку. Правило в двух копиях —
tool/lib/execution.mjsиkit/gates/_native.sh, сверка в `smoke/gate-errors.test....
v0.18.0
Выпуск про одно: AQK говорит «всё хорошо» только тогда, когда у него есть на это основание.
Пустой прогон, урезанный прогон, проверка, которой нечего было смотреть, и подменённая команда
гейта раньше выглядели как чистый результат — теперь каждое названо своим словом. И впервые
у человека есть отчёт одной страницей: что защищено, ловит ли защита на деле, лучше или хуже,
чем в прошлый раз, и какие красные новые, а какие висят давно.
Что может выглядеть иначе после обновления. Под галочками появятся строки «пусто: …» у
гейтов, которым нечего было проверять, — прогон при этом зелёный. protection-not-removed на
снимке без команд печатает совет «подмену команды не вижу»; aqk add любого гейта дописывает
строки команд в снимок, и после этого смена команды гейта без правки снимка — красная. Прогон
с --only/--skip называет себя урезанным, а не «всё объявленное зелёное». doctor --run
пишет .aqk/history.jsonl и .aqk/report.html.
Добавлено
- README стал коротким: что это, кому и когда, запуск за минуту, установка. Около ста строк
вместо семисот, логотип в начале. Всё прежнее содержание — целиком в полном руководстве
docs/guide.mdиdocs/guide.ru.md; версии и размер пакета в них сверяются той же проверкой,
что и в README. - Новое отдельно от давнего.
doctor --run, блок для агента, отчёт для человека и сводка
задания делят не зелёные гейты на сломанные только что («новое с прошлого зелёного») и
висящие давно («красный с 13.09, 20 прогонов подряд»). Возраст считается по истории прогонов.
Повод — отзыв с проекта владельца: давний долг прятал три свежие ошибки, и то, что AQK
поймал сам, никто не заметил. - Отчёт для человека одной страницей —
.aqk/report.html. Три ответа на одном экране: что
защищено, ловит ли защита на деле (по пробе), лучше или хуже, чем в прошлый раз, — и что
поручить агенту, готовыми командами.doctor --runпишет его каждый раз,aqk report --html
собирает без прогона. Один файл без сети и зависимостей. Блок для агента велит показать его
человеку. В GitHub Actions тот же прогон дописывает сводку задания (GITHUB_STEP_SUMMARY) —
без прав и без нашего действия. - История прогонов —
.aqk/history.jsonl. Строка на прогон: коммит, уровень, итог каждой
проверки и пометка урезанного прогона. Из неё отчёт считает «было → стало» по двум последним
полным прогонам и называет, что сломалось и что починено.
Исправлено
- Подмена команды гейта при том же имени больше не проходит зелёной. В одном PR команду
secrets-not-in-codeзаменили на"true"и добавили в код ключ —doctor --runговорил
«всё объявленное зелёное», код 0:protection-not-removedсторожил только имена. Теперь снимок
gates-declared.txtхранит одобренную команду строкой# run имя: команда, и расхождение с
манифестом красное, с «было» и «стало». Сменить команду можно правкой этой строки — её видно
в дифе. Снимок старого формата не роняет прогон, а говорит советом, что подмену не видит;
aqk addлюбого гейта дописывает недостающие строки и не переписывает записанные. Найдено
сверкой с судьёйkirder24-code/ai-agent-manager(цикл A5). - Урезанный прогон называет себя урезанным.
doctor --run --only …при незапущенном
красном гейте печатал «не запускались: …» и тут же «Всё объявленное зелёное.»; заголовок
отчёта говорил то же. Теперь — «Всё запущенное зелёное, но прогон урезан: не запускались …». - Прогон без единого гейта не называется зелёным. Вместо «Всё объявленное зелёное» —
«пусто: гейтов не объявлено — прогонять было нечего». - «Пусто» больше не выдаётся за «чисто». Сканирующий гейт, не нашедший ни одного файла
своего типа, молчал с кодом 0 — так же, как на проверенном и чистом проекте (10 из 13
записей). Теперь он печатает «пусто: … — проверять было нечего», остаётся зелёным, а
doctor --runпоказывает строку под галочкой. Если файлы скрыл.aqkignore, это названо.
env-secrets-not-committedиpersonal-config-not-shared«пусто» не говорят: для них
отсутствие файлов и есть чистый ответ. - Код в
vendor/,coverage/и других пропускаемых каталогах больше не определяет язык
проекта. Список пропусков был записан дважды — сорок имён у гейтов, восемь у определения
языков, — и doctor советовал записи по файлам, которые сами записи не читают. Теперь список
один, вkit/gates/_skip.sh. - Осознанно снятая защита снова видна.
protection-not-removedпечатал «совет: снято
осознанно …» с кодом 0, а прогон у зелёного гейта показывает только строки-советы и узнавал
одну метку «почини:». Строка не доходила до человека. Теперь узнаются обе, а модульная
проверка сверяет каждую метку, которую печатают гейты, с тем, что узнаёт прогон. - Неизвестное время гейта в отчёте — прочерк, а не «0.0 с». Строки истории старше поля
времени показывались нулём, то есть «гейт отработал мгновенно». Единица времени теперь на языке
отчёта: в английский попадала русская «с». - Время в отчёте — местное. Шапка и подписи графика показывали время по Гринвичу: прогон в
18:47 выглядел как 13:47, то есть как чужой. - Мусорный предел больше не выключает гейт.
AQK_MAX_DEPTH=abcуcomplexity-limitи
AQK_DUP_LINES=abcили-3уduplicate-codeдавали зелёный на заведомом браке без единой
строки. Теперь — код 2, «проверка не состоялась», с именем переменной. deps-are-pinnedвидит обычныйpackage.jsonи конвейер, выключивший lock-файл. Первая
зависимость на новой строке принималась за «зависимостей нет». Теперь ещё иpnpm install --no-frozen-lockfileв.github/workflowsприpnpm-lock.yaml— находка с файлом и строкой.- Порог
--minиз мусора — отказ до прогона.--min -1проходил при любом уровне,--min ""
становился нулём. Теперь допустима только ступень от 0 до верхней, как у--jobs. - Кэш ruff больше не отдаёт вчерашнее «чисто». Ключ его кэша — время изменения файла: правка,
после которой время вернули прежним (cp -p,tar,unzip), проходила гейт. У рецептов ruff
теперь--no-cache. - Конфигурация анализатора больше не выключает объявленный гейт. Исключение пути в конфиге
ruff, pylint и vulture снимало находку при нарушении в коде; рецепты теперь отменяют его. - Переписанное ожидание теста называется вслух, а прогон предупреждает, когда индекс и рабочая
копия расходятся: зелёный вердикт относился бы не к тому, что уйдёт в коммит.
npx agent-quality-kit doctorv0.17.0
Выпуск про одно: зелёный результат больше не скрывает сломанный прибор. Авария анализатора,
недоступная история и неверный путь Git-хука теперь отделены от чистого результата; новый гейт
ловит разъехавшиеся копии сводов агента; проверки конвейера видят трубы и husky-хуки, которые
гасят провал.
Что может выглядеть иначе после обновления. test-not-adjusted вернёт ошибку проверки, если
указанной базы нет или она не является коммитом. Native-анализатор, завершившийся аварийно, не
позеленеет после фильтрации знакомого долга. aqk ratchet не создаст baseline из неполного
аварийного вывода. Проект с двумя похожими корневыми сводами агента получит находку, только если
они действительно разошлись; указатель одного файла на другой и независимые документы не
обвиняются.
Добавлено
entry-docs-agree— разъехавшиеся копииAGENTS.mdиCLAUDE.mdвидны машине. Порог
проверен на 85 парах из 300 чужих репозиториев: четыре находки разобраны вручную, ложных среди
них нет. Указатели вида@AGENTS.md, отличие только в имени агента и два самостоятельных
документа проходят.- Постоянная запись храповика
~ <ключ>. Нестабильная находка больше не исчезает после
одного тихого прогона; рядом обязательна причина# постоянная: ..., а снимает запись человек. - Проверка недоказанных рецептов каталога. Приёмка теперь поимённо показывает рецепты, для
которых нет собственного красного и зелёного образца, вместо молчаливого впечатления полной
доказанности.
Исправлено
- Авария анализатора не превращается в успех после фильтрации. Общая shell-классификация
различает чистый результат, находку и отказ прибора до фильтра путей и baseline. Храповик
сохраняется побайтово при ошибке, а создание baseline запрещено. Shell- и Node-реализации
сверены на всех 256 кодах завершения для пяти инструментов. test-not-adjustedбольше не зеленеет без доступной базы сравнения. Неверный ref и объект,
который не является коммитом, дают отдельный исход «проверка не состоялась».- Git-хук ставится в настоящий путь Git. Учитываются worktree и
core.hooksPath, включая
относительный и абсолютный путь; чужой существующий хук не переписывается. - Отпечаток доказательства не склеивает разные входы. Отсутствующий файл, буквальный текст
<missing>и границы записей кодируются раздельно. ci-actually-failsвидит погашенный провал в трубе и husky-хуке.pytest | teeбез
pipefail, а такжеlint-staged || trueв блокирующем хуке больше не выглядят защитой.aqk noteкоммитит только свой журнал и не пушит без--push. Чужой staged-дифф не
захватывается, внешнее действие требует явного флага.- Советы выбираются по основному языку проекта. Служебные скрипты больше не заставляют
ставить Python-рецепт в C#- или Go-проект; порог снят с 35 чужих репозиториев. - Сверка
coversне подтверждает выключенное правило линтера.ignore,offи0
учитываются, а итоговые корзины считаются по фактическому вердикту. - Baseline называет свою границу. Число применимых проверок описано как оснащение для работы
машины, а не оценка качества проекта.
Исследовано и отклонено
- Разобраны все 129 правил glint и каталоги популярных линтеров; новые записи без подтверждённого
живого класса в AQK не добавлялись. - Форма «ошибка напечатана, процесс вернул 0» проверена на 61 репозитории: подтверждённых случаев
нет, поэтому гейт по одной правдоподобной идее не создан. - Полностью прочитан
smixs/code-quality; внедрены только механизмы, для которых воспроизведён
собственный дефект AQK. Остаток первого исследовательского цикла честно остаётся в roadmap.
npx agent-quality-kit doctorv0.16.0
Выпуск про одно: комплект перестал верить сам себе на слово. Десять раз наши собственные
утверждения не пережили проверки — и каждый раз побеждала проверка.
Сперва четыре случая, где мы обвиняли или молчали напрасно:
doctorпри первой встрече с чужим проектом ставил зелёную галочку проверке, выключенной
прямо в её же строке (node --test || true). Теперь читает тело скрипта, а не имя;- гейт
hook-actually-firesзеленел на хуках, указывающих на скрипты, которых нет. Нашёл это
чужой линтер, прогнанный по нам, а не наши 192 проверки; - гейт
ci-actually-failsобвинял напрасно: замер на 70 чужих конвейерах дал одно срабатывание,
и оно оказалось ложным; - сканер чужих репозиториев нашёл ещё три ложных — и все три починены раньше, чем ушло хоть
одно письмо.
Затем шесть — все одного рода: правило написано для чужих и не применено к себе. Их нашла
попытка поставить комплект в большой зрелый проект, а не наш прогон из двух сотен проверок. Они
разобраны ниже по одному; короче всего так: объявленный гейт делал чужие проверки невидимыми,
vitals засчитывал чужой хук за наш, smoke.sh выдавал запрет среды за пятнадцать падений,
предел времени гейта жил в четырёх копиях без способа решить иначе, report падал там, где
нечего записать, а requires был доступен нашим записям и недоступен гейтам проекта.
Что может выглядеть иначе после обновления. Если в вашем package.json проверка выключена в
самой команде (|| true, --exit-zero, тело из одной печати), doctor теперь скажет об этом
крестом и не предложит вписывать её в манифест. Если у вас объявлены хуки Claude Code, чьи файлы
отсутствуют, hook-actually-fires покраснеет — раньше молчал. Если у вас есть свои проверки в
Makefile, package.json или .pre-commit-config.yaml, doctor назовёт их и тогда, когда
гейты уже объявлены, — раньше он о них молчал. Если AQK не вызывается из вашего
.git/hooks/pre-commit, vitals скажет об этом прямо, а не напишет «прописан». Все перемены в
одну сторону: инструмент стал говорить там, где раньше молчал.
Удалено
- Записи
entry-links-existиno-phantom-packageубраны из каталога. Обе читали свободный
текст, а не опознавали конструкцию: разметку и прозу вокруг команд установки. Замер по 400
чужим репозиториям 2026-09-14/15 дал у них двенадцать ложных срабатываний и ни одной
подтверждённой настоящей находки. Хрупкую запись не чинят, её убирают — иначе каждый следующий
замер приносит новое исключение, а доверие к остальным записям падает вместе с ней. Правило,
по которому это решено, записано вSPEC.md§6
Исправлено
-
Объявленный гейт больше не прячет проверки, которые у проекта уже есть. Замер 2026-09-16
по двенадцати чужим репозиториям: у шести зрелых (requests,httpx,fastapi,black,
express,flask)doctorчитал в их файлах от одной до трёх настоящих проверок — и всё
исчезало, стоило объявить ОДИН гейт. Итог говорил «держит машина 0» проекту с настоящим
pre-commit и Makefile: чем больше человек настроил, тем меньше мы о нём знали. Отсев теперь
по КОМАНДЕ, а не по факту «манифест не пуст»: имена гейтов у проекта свои, по ним совпадения
не будет никогда. Это вторая встреча с тем же классом — первый чужой пользователь назвал
«применимо, но не поставлено: 5» неправдой ещё 2026-09-08, и ответом стало полеcovers,
которое заполняется руками и потому в зрелом проекте не заполнено никем -
vitalsбольше не засчитывает чужой хук за подключённый AQK. Проверялось ИМЯ в теле
хука (/pre-commit|aqk/i), а слово «pre-commit» у хука фреймворка есть всегда: в живом
проекте AQK не вызывался ни разу, а строка говорила «прописан в .git/hooks». Состояний
теперь четыре — не знаем · хука нет · хук есть, но не наш · подключён, — и подключение
считается обоими честными способами: прямым вызовом в теле и нашим хуком через
.pre-commit-config.yaml. Как это делают снаружи: pre-commit узнаёт свой хук по маркеру в
теле (is_our_script()), а не по имени -
smoke.shотказывается целиком, когда мерить нечем. В песочнице, запрещающей
подпроцессам Node запускать git и npm, прогон давал 15 «падений» из 123 — их не было.
Человек час разбирал несуществующие дефекты. Теперь предполёт спрашивает того же, кого
спросит прогон, и при отказе выходит кодом 3 — тем же, которым pytest отделяет внутреннюю
ошибку от провала теста. Частичный прогон не печатается: 108 зелёных из 123 при недоступном
git — это не «почти всё хорошо», а «мерить было нечем» -
reportиdoctor --runне падают там, где нечего записать. В рабочей области, где
.aqk/не создать (read-only контейнер, чужой конвейер, каталог под ревью), команда падала
с EROFS, не напечатав ни строки, — побочное действие отменяло то, ради чего её звали.
Теперь результат печатается, а несохранение называется вслух:contextиpromptчитают
отсутствиеlast-run.mdкак «прогона не было», и разницу надо видеть -
Ложное срабатывание нашего же
test-not-adjusted. Гейт краснел на ДОБАВЛЕННОМ
комментарии:checkwashпринимает строковый литерал"\n"за имя тестового юнита, и файл
с двумя такими литералами на любом сдвиге строк получаетTEST_DISABLEDуровня high.
Воспроизводится на чистом репозитории в шесть строк, в 0.2.13 и 0.3.4 одинаково. У себя
обошли устранением настоящего повтора, но цена записи названа вслух в её README: тот же
ложный приговор может прилететь любому проекту с обычнымsplit("\n")в тестах -
hook-actually-firesпроверяет, что файл команды существует. Хук, указывающий в пустоту,
не срабатывает никогда, а гейт с таким именем говорил «чисто». Граница узкая: красится только
относительный путь со слэшем; программа из PATH (npx,bash -c …) не судится — у неё нет
пути; абсолютный путь пропускается как относящийся к чужой машине -
ci-actually-failsбольше не обвиняет напрасно. Гашение красится, только если погашенная
команда — последняя в блоке.pnpm eslint src > out.txt || true, а строкой нижеdiffс
эталоном — это законный уклад: линтер ОБЯЗАН выйти ненулевым, вердикт выносит следующая команда -
entry-links-existне красит рабочие ссылки.../../releases— так сам GitHub предлагает
ссылаться на выпуски, путь считается от адреса файла в вебе; строка запроса
(assets/demo.gif?raw=1) больше не читается как часть имени файла -
no-phantom-packageне обвиняет подстановку. «Когдаnpm install @types/xxxне находит
пакет типов» — это многоточие, сказанное словами, а не выдуманный пакет
Добавлено
-
requires:в манифесте проекта — чем работает гейт, когда по команде этого не видно.
Гейт видаdocker run … promtool test rules …заставлялvitalsсмотреть на первое слово и
отвечать «инструменты на месте». Поле для этого существовало, но читалось только из
<samples>/<гейт>/gate.yml— то есть было доступно нашим записям каталога и недоступно
гейтам проекта, у которогоsamplesпуст по построению. Соглашения снаружи нет и это сказано
вслух: у pre-commit ровно эта просьба закрыта нерешённой (issue #2042), у lefthook такого
ключа нет вовсе, — поэтому распространена своя форма, та же, что уcovers:иgroups: -
AQK_GATE_TIMEOUT— предел времени гейта можно назвать своим. Пять минут были вписаны в
четырёх местах, и способа решить иначе не было вовсе: живой проект, чей полный verify идёт
дольше, просто не стал объявлять свою главную проверку гейтом. Умолчание не изменилось и не
выдумано — столько же ждёт quality gate у SonarQube; переопределение переменной среды — тоже
их способ и способ GitLab. Поляtimeoutу гейта в манифесте нет намеренно: его нет ни у
pre-commit, ни у lefthook, а долгую проверку честнее объявить отдельной командой -
Методичка
operational-gates.md— карта эксплуатационных арбитров живого
Django/Celery-проекта: OOM, N+1, топология очередей, реестр метрик, нагрузка и soak; что
закрыто машиной, что только видно, и где граница. Шесть ссылок на первоисточники сверены
запросом, а не по памяти -
Первый запуск называет проверку, которая не может провалиться.
doctorчитал ИМЯ скрипта
и печатал каноничнуюnpm testс зелёной галочкой, ни разу не заглянув в его ТЕЛО, — а
выключатель стоит именно там. На репозитории, где выключено всё (node --test || true,
ruff … --exit-zero,"test": "echo todo"), первый экран говорил «у вас уже есть 2 проверки».
Теперь такая проверка помечена крестом, причина названа дословно той строкой, которую человек
найдёт у себя глазами, и её больше не предлагают вписать в манифест: объявленная проверка,
которая не может покраснеть, превращает дыру в зелёную галочку, за которую ручается машина.
То же знание ушло в блок для агента — иначе агент впишет её сам. Граница узкая и взята у гейта
ci-actually-fails:|| trueв СЕРЕДИНЕ команды — идемпотентность вспомогательного шага, а не
выключенная проверка -
aqk feedback --send— отзыв уходит одной командой. Отправляет вашgh, вашей учётной
записью GitHub, комментарием в открытое обсуждение проекта. Без браузера, без формы, без
регистрации. Без флага наружу не уходит ничего — и это утверждение держит машина
(smoke/feedback-send.test.mjs, подделкаghчерезAQK_GH), а не обещание в документации:
мутацией проверено, что безусловная отправка роняет проверку. Своя строка —feedback --send "ваш текст". Согласие живёт в самом флаге: агенту в умениях сказано показать текст человеку и
спросить, а флаг самому не добавлять -
Своя витрина плагинов.
.claude-plugin/marketplace.json— репозиторий раздаёт плагин сам:
/plugin marketplace add arsen-ask-lx/Agent_Quality_Kitи/plugin install aqk@agent-quality-kit
работают без чьего-либо одобрения -
Размер пакета сверяет машина. Обещанное в README число сравнивается с
npm pack --dry-run,
округлённо до десятой доли мегабайта. До этого оно врало трижды: «230 КБ» в коде и «574.1 kB»
в обоих README при настоящих 692
npx agent-quality-k...v0.15.0
Выпуск про одно: комплект перестал молчать о себе. Сломанная проверка больше не зеленеет при
--since — отказ прибора теперь отличается от находки о коде везде: в прогоне, в отчёте, в блоке
для агента и в пометках pull request. И появилась единственная плата, которую комплект просит:
один ответ автору — по делу, один раз на проект и с уже собранным письмом.
Что может выглядеть иначе после обновления: гейт, который не смог отработать, при --since
остаётся красным (раньше мог позеленеть) и называет причину словами; в .aqk/last-run.md у такого
появился свой знак ?, а блок для агента печатает его отдельной строкой; совещательный гейт
своим таймаутом больше не роняет прогон, но назван вслух; один раз на проект doctor или блок
для агента печатают строку с просьбой об отзыве — выключается AQK_FEEDBACK=0.
Добавлено
-
aqk feedback— единственная плата за комплект: один ответ автору. Команда собирает из
последнего прогона и пробы короткий отчёт — версия, уровень, стек, что покраснело, чего
комплект НЕ СМОГ проверить, какие классы брака здесь не ловит никто — и даёт предзаполненную
ссылку на задачу. Без путей, без кода и без имени репозитория; человек видит глазами всё,
что отправляет, и отправляет сам. Исходящих запросов у комплекта по-прежнему ровно один —
про свежесть версии.Просьба об отзыве печатается один раз на проект и только когда есть что рассказать:
«AQK не смог проверить X» (самое ценное), «проба нашла классы, которые здесь не ловит никто»,
«комплект поймал вот это». Нечего рассказать — просьбы нет вовсе. Агенту она приходит в блоке
contextвместе с оговоркой «скажи один раз и не настаивай», человеку — строкойdoctor.
Выключатель —AQK_FEEDBACK=0.Почему: замер 2026-09-14 — 1342 скачивания в неделю в npm, но версии качаются равномерно,
включая прожившую двадцать пять минут, то есть это зеркала и сканеры; на GitHub за две недели
семь уникальных посетителей и ноль чужих комментариев за всё время. Просьба существовала, но
печаталась приinit— до того, как комплект сделал хоть что-то полезное -
Третий знак в отчёте прогона:
?— «не смогли проверить»..aqk/last-run.mdразличает
находку (✘) и отказ самой проверки (?), и блок для агента печатает их разными строками:
гейт, который не сумел отработать, — не находка о коде, и агент, прочитавший его как находку,
пойдёт чинить исправный файл. «Чисто» говорится только когда пусты оба списка
Изменено
- Одно знание «мы это человеку уже показывали» вместо двух. Ограничитель обращений — совет,
проверка версии, просьба об отзыве — сведён вtool/lib/ask.mjs: таблица видов объявляет, где
лежит отметка (проект или дом) и через сколько можно повторить. Имена файлов прежние, поведение
прежнее; связь с.gitignoreтеперь сторожит проверка — отметка, не названная вRUNTIME_FILES,
уехала бы в чужой коммит - Формат отчёта прогона — в одном модуле. Писал его
doctor, разбиралcontext— два файла,
которые друг о друге не знают, держали один формат. Теперь и запись, и разбор вlib/run.mjs
Исправлено
- Сломанная проверка больше не зеленеет при
--since. Сужение до дифа шло по путям в выводе
гейта — и под него попадал не только чужой старый долг, но и гейт, который НЕ СМОГ отработать:
нет инструмента, неожиданный код, убит сигналом. Такой гейт называет в жалобе какой-нибудь путь;
если путь не в дифе, строк не оставалось и прогон печатал зелёную галочку. Теперь исход запуска
определяется ДО разбора вывода — тем жеclassify/findingCodes, что уже считаютprove
(у vulture находка это 3, у pylint битовая маска, у незнакомой команды только 1): сужать дифом
можно находку, у сбоя места в коде нет. Строка прогона называет причину словами — «не смогли
проверить: код 2 — у этой команды это сбой, а не находка» — и показывает первые строки жалобы
инструмента. Совещательный гейт своим сбоем прогон по-прежнему не роняет, но назван вслух:
раньше на таймауте ронял. В pull request сбой даёт общую пометку гейта, а не пометку у строки
невиновного файла. Параллельный прогон (--jobs) терялsignalи объяснил бы то же событие
иначе — поправлено. Найдено внешним разбором соседнего инструмента (аудит Runcap, 2026-09-13):
свои девяносто проверок знали этот класс отказа и проверяли его в гейтах, но не на дороге через
флаг сужения
npx agent-quality-kit doctorv0.14.0
Выпуск про одно: от диагноза — к действию. aqk prompt пишет агенту готовое задание с
командой-арбитром у каждого пункта; находки гейтов видны пометками прямо в pull request; learn
показывает, что вам приходится повторять агенту, — прежде всего правило, которое уже записано и
всё равно не держится. Закрыт остаток отзыва с живого проекта: договор API в коде, язык вывода
по своду, «чего уровень не доказывает», короткий doctor. Новая запись каталога
entry-commands-exist — команды из свода существуют (9 из 99 публичных репозиториев с AGENTS.md
велят скрипт, которого нет).
Что может выглядеть иначе после обновления: doctor по умолчанию короче — пройденное и
неприменимое свёрнуты в строку, поимённо по --verbose или AQK_VERBOSE=1; без поля lang: язык
вывода берётся из AGENTS.md/CLAUDE.md/README.md, а не из локали машины; в GitHub Actions
упавшие гейты печатают строки ::error/::warning — это пометки для pull request, вердикт от них
не меняется; под уровнем от AQK-1 — две строки о том, чего он не доказывает.
Добавлено
-
Самопроверка на наборе настоящих случаев (
tool/selfcheck/smoke/corpus.test.mjs). Десять
минимальных воспроизведений того, что мы видели на живых проектах, в журнале и в разборах
соседей — у каждого назван источник и записан ожидаемый ответ: близнецы с настоящими и
поддельными воротами, свод с удалённым скриптом, договор в коде сtscи без,CLAUDE.mdс
windows-переносами, русский свод безLANG, определения записей, разложенные в проект. На
каждом случае все 24 переносимые записи обязаны ответить «чисто» или «находка», а не «не
смогли». Семь секунд; три нарочно испорченных ожидания — три красных -
Находки гейтов — пометками прямо в pull request. В GitHub Actions упавший гейт, чья
находка называет файл, даёт красную пометку у этой строки дифа вместе со своим «почини: …»;
совещательный — жёлтую; находка без файла — общую пометку гейта. Не больше десяти каждого вида
за прогон, остаток — числом в логе. Формат сверен с документацией GitHub, экранирование — с
официальным@actions/core. Идея — из разбора AgentLint, у которого пометки есть, но на
близнецах их проверки одинаковы для рабочих и нерабочих ворот -
learnпоказывает, что вам пришлось повторять. Реплики, где вы сами сказали «я же
говорил», «опять», «снова», идут первым блоком; такая реплика, совпавшая с правилом свода, —
отдельно: «записано, а поправлять всё равно приходится», правилу нужен сторож. Идея — из разбора
AgentLint (их SS2 сопоставляет поправки с правилами по словам). Замер на логах владельца
отверг их способ: из 45 поправок к записанным правилам относятся от силы две. Пометка повтора
самим человеком оказалась надёжнее: на двух проектах 8 таких реплик, настоящих норм 7, а
прежний отбор по словам «всегда»/«никогда» не ловил ни одной. «Опять» в вопросе («че опять
rust?») — недоумение, а не норма, и не считается -
aqk prompt— одно задание для агента. Между диагнозом и действием не было моста:
doctorпишет человеку,contextговорит агенту «как дела», а «почини вот это» человек
пересказывал сам. Теперь сверху — правила поведения (команды не выдумывать, чинить код, а не
проверку, решения владельца — спрашивать), дальше до пяти пунктов по весу: красные гейты, брак,
подсаженный пробой и не пойманный, свои проверки проекта, свод, невидимый Claude Code, записи
каталога — эти как предложение владельцу, а не приказ. У каждого пункта — команда, которая
докажет «готово». Прогона не было или он устарел — первым пунктом «прогони», а не пустое
«всё чисто». Идея из разбора agentlint; их «проверь» — «балл вырос», у нас — команда-арбитр -
Запись
entry-commands-exist: команды из свода существуют в проекте. Агент берёт команды
из свода дословно; скрипт удалили — свод продолжает велеть «npm run lint:cli». Замер на 99
публичных репозиториях сAGENTS.md: в 9 свод называет скрипт, которого нет ни в одном
package.json; в двух история показывает механизм — скрипт удалён, строка в своде осталась.
Сверяютсяnpm|pnpm|yarn|bun run X(блок"scripts"всехpackage.json),make X(цели всех
Makefile),just X(justfile).makeиjust— только внутри кода: «make sure» не
команда. У соседа, agentlint, то же правило знает только npm — на живом проекте с шестнадцатью
целямиmakeв своде оно молчит по построению -
doctorназывает свод, которого не видит Claude Code. Документация Claude Code: «reads
CLAUDE.md, not AGENTS.md». Проект с.claude/и сводом только вAGENTS.md— или с
CLAUDE.md, которыйAGENTS.mdне подключает, — получает строку с готовой починкой:
@AGENTS.mdвCLAUDE.md. Где Claude Code не настроен, строки нет: Codex и Cursor читают
AGENTS.mdсами
Исправлено
- Договор API в коде больше не невидим. Отзыв с живого проекта: схемы zod в общем пакете,
сервер на@fastify/type-provider-zod— аdoctorписал «спецификации API не видно»,
потому что знал договор только по имени файлаopenapi*. Теперь договором считается и
зависимость вpackage.json: tRPC, ts-rest,@hono/zod-openapi, провайдеры типов Fastify.
Арбитр такого договора — проверка типов;api-contract-has-arbiterкраснеет, еслиtsc
(vue-tsc,tsgo) не запускает ни одна команда. Одинzodдоговором не считается.
На том же проекте запись теперь применима и зелёная:tsc --buildстоит вscripts - Язык вывода — по языку проекта, а не машины. Отзыв с живого проекта: свод и методички на
русском, Windows безLANG— весь вывод английский, пока не впишешьlang:руками. Теперь
без поляlang:язык берётся из прозыAGENTS.md,CLAUDE.mdиREADME.md(код, пути и
адреса не считаются), и только если текст молчит — из локали.AQK_LANGиlang:сильнее - Под уровнем стоит, чего он не доказывает. Отзыв с живого проекта: «AQK-3, All levels
reached» при конвейере, который ни разу не запускался. Ступени меряют оснащённость — гейты
показаны на образцах каталога; про файлы проекта знает только проба. Теперь при уровне от
AQK-1doctorпишет две строки: что проба знает о браке в ваших файлах (не запускалась · не
поймала такие-то классы · поймала все подсаженные) и что прохождение конвейера отсюда не
видно. Проба записывает в отметку, сколько классов поймано и у скольких поимка не доказана.
Планку ступеней не подняли: отметка пробы в.gitignore, в конвейере её нет — «AQK-2 только
после пробы» уронило бы уровень иbadge --checkу всех разом doctorкороче по умолчанию, поимённо — по--verbose. Отзыв с живого проекта: сто
строк вывода, большая часть — зелёные галочки, и красное теряется между ними. Теперь прошедшие
гейты, записи, которые держит машина, и неприменимые сворачиваются в строку со счётом;
упавший, совещательный, совет и «что поставить» видны всегда. На этом репозитории без--run
— 49 строк вместо 75, под--runтридцать зелёных строк становятся одной. В конвейере —
AQK_VERBOSE=1
npx agent-quality-kit doctorv0.13.0
Выпуск про одно: всё, что кит печатает зелёным, доказано — отзыв с живого проекта на
TypeScript и Biome нашёл места, где это было не так. Проба больше не засчитывает поимку, когда
гейт упал по своей причине; заявка covers: сверяется правилами того линтера, которым закрыт
гейт, — Biome и eslint, а не только ruff; неустановленная запись — ○, а не красный крест.
И то, что нужно проекту, где проверок больше тридцати: группы и --only / --skip для гейтов,
которым нужен стенд, --jobs N для параллельного прогона, служебные файлы .aqk/ сами уходят
в .gitignore. Новая запись env-secrets-not-committed — пароли в .env, которых не видит ни
один сканер секретов; её доказательство — случаи из журнала, а не придуманный образец.
Что может выглядеть иначе после обновления: init дописывает строки в .gitignore;
отсутствие .aqk/docs и .aqk/rules больше не роняет прогон; внутри конвейера (CI=true)
проба сама не запускается — ставьте её отдельной задачей.
Исправлено
- Проба засчитывает «поймано» только по делу. Раньше «гейт покраснел после подсадки» и
«гейт поймал брак» были одним и тем же: код возврата сравнивался, вывод выбрасывался. Отзыв с
живого проекта на TypeScript и Biome: класс «цвет из токена темы» отмечен пойманным линтером,
хотя Biome цвета не проверяет, — подсаженный кусок ломал форматирование. Итог «каждый класс
кем-то ловится» был ложной уверенностью. Теперь поимка подтверждается ПАРОЙ, тем же приёмом,
каким мы проверяем чужие гейты: гейт обязан назвать подсаженный файл и промолчать на ЗЕЛЁНОМ
образце той же записи в том же месте. Краснеет и на зелёном — «падает от самой подсадки»;
файла не назвал — «упал по своей причине»; оба — «поимка не доказана», а не «поймано».
Воспроизведено на проекте сbiome check .: старая проба — «ловит: lint», новая — «покраснело:
lint (краснеет и на зелёном образце) — поимка не доказана»; настоящая поимка осталась поимкой - Заявка
covers:сверяется правилами ТОГО линтера, которым закрыт гейт. Раньше коды ruff
(T20,C901,BLE) искались в любом конфиге, и в проекте на Biome заявка «lint держит
no-print-in-prod» была «не подтверждена» всегда — хотяnoConsoleстоял. Теперь линтер гейта
узнаётся по команде, по npm-скрипту, который она зовёт, или по единственному конфигу линтера;
правила берутся на его языке: ruff — коды из рецепта, eslint — имена правил из рецепта,
Biome — новое поле записиbiome_rules(имена сверены по схеме конфигурации Biome 2.5.12).
Исходов стало три: «не подтверждена»; «неверна — у линтера нет такого правила» (у Biome нет
правила под TODO); «проверить не умею» — тускло, а не обвинением. На живом проекте с Biome
три ложных «не подтверждена» ушли - Проба сама не запускается внутри
doctor --runв конвейере. Раз в сто коммитов она
добавляла 2–3 минуты в случайный прогон CI. Теперь в конвейере (CI,GITHUB_ACTIONS, …)
печатается одна строка — когда проба подошла по сроку — с советом поставить её отдельной
задачей;AQK_PROBE=1включает прежнее поведение. У человека проба по-прежнему идёт сама vitalsспрашиваетnpm view, если прямой запрос к реестру не прошёл.fetchв Node не
знает прокси и зеркала из.npmrc, иvitalsписал «не достучался до реестра» там, где
npm viewработал- В
aqk helpуvitalsбылоundefinedвместо описания. Исправлено, и заведён сторож:
у каждой команды справки обязано быть описание на обоих языках - Проба больше не пишет «рабочее дерево не трогается», записывая
.aqk/last-probe.md.
Теперь: «файлы проекта не меняются; итог пробы пишется в.aqk/last-probe.md»
Добавлено
-
doctor --run --jobs N— независимые гейты параллельно. 34 гейта у живого проекта шли друг
за другом больше минуты, «а быструю проверку, которую долго ждать, перестают запускать». На этом
репозитории 30 гейтов: около 110 с по одному, 68 с с--jobs 3. По умолчанию выключено: гейты,
пишущие в одни файлы, вместе падали бы через раз. Каждый гейт выполняется в рабочем потоке тем
жеspawnSyncс тем же таймаутом, что и раньше; вывод — в порядке объявления -
Группы гейтов и
doctor --run --only / --skip. Отзыв с живого проекта: гейт цены меряет
план на засеянной базе — объявишь, и он валит прогон без стенда; уберёшь, иpromise-has-gate
справедливо ругается. Прогон бывал только «всё или ничего». Теперьgroups: { stack: [cost] }
в манифесте и--skip stackв быстром прогоне; принимаются и группы, и имена гейтов.
Пропущенные названы в выводе и в.aqk/last-run.mdстрокой «~ не запускался» — блок для
агента читает их как «неизвестно», а не как зелёные. Неизвестное имя — отказ с причиной -
Совет — на языке линтера проекта. «Начните с трёх» и находки пробы советовали eslint
проекту на Biome: комплект читалpackage.jsonиMakefile, но неbiome.json. Теперь при
biome.jsonв корне команда даётся для Biome — одно правило разово:
npx @biomejs/biome lint --error-on-warnings --only=suspicious/noConsole .. Флаг
--error-on-warningsобязателен: правило вне рекомендованных Biome ставит на
«предупреждение», и без флага команда выходила с нулём, напечатав находку. Имена правил и
поведение проверены на Biome 2.5.12 -
Запись
env-secrets-not-committed: пароли из.envне лежат в git. Замер: на
закоммиченном.envпароль, придуманный человеком (Sup3rS3cret2024), не видят ни наш
secrets-not-in-code, ниgitleaks8.30.1 — у него нет ни формата, ни энтропии;.env.local
не видит дажеdetect-secrets. Два правила:.env.local/.env.*.localв git — всегда
находка; остальные.env*— если внутри ключ-секрет с настоящим значением. Не «любой.env»:
dotenv рекомендует коммитить зашифрованный dotenvx, Next.js —.env.test, в проектах на Vite
коммитят публичные настройки. Значение секрета в вывод не печатается. Замер на 11 живых
репозиториях (включая Vite с 16 закоммиченными.env) и на пяти с закоммиченным
.env.production.localиз поиска кода GitHub: гейт краснеет на всех пяти, четыре находки
настоящие, два ложных срабатывания (фикстуры вtests/и демо вplaygrounds/) закрыты
исключением. Запись зрелая: случай в журнале шишек -
Блок для агента говорит, что делать дальше и когда какую команду запускать. Раньше
contextотвечал только «как дела»: уровень, красное, проба. Три первых шагаdoctor
знал, а в контекст они не попадали; карта команд жила только в--full, в восьми тысячах
токенов, где агент её пролистывал. Теперь в коротком блоке:- «Дальше» — до трёх шагов из того же расчёта, что у
doctor: завести стандарт, если
.aqk.ymlнет; объявить проверки, которые у проекта уже есть; закрыть классы, которые
проба подсадила и ваши проверки не поймали; «начните с трёх». У каждого — готовая команда - «Когда что» — правила «ситуация → команда»: перед коммитом (зависит от того, стоит ли
хук), после правки проверки (aqk prove), метка арбитра в своде, «проверка мешает — не
ослабляй, спроси владельца», «готово =aqk report --since main»
Форма — по документации Claude Code: «чем конкретнее и короче инструкции, тем стабильнее
Claude им следует»; «"Runnpm testbefore committing" instead of "Test your changes"».
Блок вырос с ≈375 до ≈500 токенов - «Дальше» — до трёх шагов из того же расчёта, что у
Изменено
initдописывает служебные файлы.aqk/в.gitignore.last-run.md,last-probe.md,
advice-shown,update-checked— состояние машины, их переписывает каждый прогон. Отзыв с
живого проекта:last-run.mdоднажды закоммитили, и каждыйmake checkоставлял изменённый
файл. Методички и правила в.aqk/по-прежнему коммитятся. Для тех, кто поставил раньше,
doctorназывает служебный файл, который видит git, — с готовой командойgit rm --cached- Неустановленная запись каталога — ○, а не ✘. Крест в зелёном прогоне глаз читает как
провал, и через неделю человек перестаёт смотреть на красное вообще. ✘ теперь значит одно:
упало или пропустило брак - Нет
.aqk/docsили.aqk/rules— прогон не краснеет. Методички — пособие, проект вправе
держать их где-то ещё; пункт показан как совет (○). Точка входа,.gitignoreи.git
остаются обязательными - Первый
doctorпоказывает главное вверху. Раньше сначала шёл список всех записей по две
строки на каждую (вторая — «поставить: aqk add …»), и на requests «у вас уже есть» и «начните с
этих трёх» начинались со строки 84 из 102. Теперь порядок: что уже держит → что у вас уже есть →
что проверки пропустили → начните с трёх → остальные записи по одной строке с одной общей
подсказкой → неприменимое. Подсмотрено у agentlint: у них первыми идут пять главных исправлений
npx agent-quality-kit doctorv0.12.0
Выпуск про одно: первый же запуск показывает, что у вас хорошо, что нет и с чего начать —
вместо двадцати одинаковых крестов и минуты пустого экрана. doctor видит проверки, которые у
проекта уже есть (у восьми живых python-проектов из восьми, а не у трёх), называет брак, который
ваши проверки пропустили в ваших же файлах, и предлагает три первых шага с готовой командой.
И одно исправление, ради которого выпуск не стал ждать недели: на Windows гейты больше не
уезжают в WSL — отчёт с живого проекта, где make check краснел не из-за кода.
Добавлено
doctorпоказывает проверки, которые у проекта УЖЕ есть. Если гейтов в манифесте нет,
он читаетpackage.json(scriptstest,lint,typecheck,check…) иMakefileи
печатает их галочками с источником — и готовую строку дляgates:. Раньше проект с eslint,
mocha и конвейером видел «держит машина 0»: мы считали только свои записи. Предлагаем, а не
вписываем — гейт в чужом манифесте без спроса был бы нашим решением в чужом файле- «Начните с этих трёх». Когда не закрыто больше трёх записей,
doctorвыбирает три: сперва
те, что родились из настоящего отказа (есть запись вincidents/) и закрываются одной
готовой командой под ваш язык. У каждой — команда, которую можно выполнить прямо сейчас, и
адрес инструмента (ruff, eslint, gitleaks, vulture…), и слово про хук перед пушем - Python-проекты тоже видят свои проверки. Кроме
package.jsonиMakefileчитаются
.pre-commit-config.yaml(одной командойpre-commit run --all-files, хуки названы
поимённо), окружения-проверки tox изtox.iniиpyproject.toml(tox -e lint,style,
typing— матрица версий не предлагается) и исполняемыеscripts/test|check|lint. Замер на
восьми живых проектах (requests, click, flask, httpx, black, fastapi, pydantic, rich): свои
проверки видели три из восьми, теперь — все восемь. Шаги конвейера не читаются намеренно:
uv run --locked --group … ${{ matrix.x }}работает только в том конвейере doctorпредостерегает находками пробы, ничего не запуская. Проба подсаживает брак в
копию ваших самых чинимых файлов и знала, какой класс ваши проверки пропустили, — но в
отметку писала одно число, и человек вdoctorне видел ничего. Теперь отметка несёт имена
классов и файлы, аdoctorпечатает их над «начните с этих трёх»:✘ swallowed-error ← src/utils.pyи команду, которой поймать прямо сейчас. Три случая не сливаются: гейт стоял и
проба его гоняла — «стоит, но здесь не ловит»; гейт объявлен, но проба его не гоняла
(поставлен позже или медленный) — «покажет следующая»; гейта нет — совет. Пробы не было —
одна строка о том, что она сделает. Блок для агента (context) называет те же классы по
имени- Поле
tool:у записи каталога — адрес инструмента, которым она проверяет. В совете
показывается адрес того инструмента, которым начинается команда: python-проекту — ruff, а не
ruff и eslint - Строка «идёт» во время
doctor --run. Пока гейт работает, видно, какой именно и какой по
счёту:⋯ smoke [2/10] идёт…; по завершении строка сменяется на ✔ или ✘. То же на секунды
доказательства перед уровнем. Только в терминале: в пайп и в конвейер не пишется ни байта
Исправлено
- Windows: гейты больше не уезжают в WSL. На Windows 10/11 в
System32лежитbash.exe—
заглушка WSL, и в PATH она стоит раньше Git Bash (установщик Git по умолчанию кладёт туда
толькоGit\cmd). Командаbash kit/gates/x/check.sh .запускалась в Linux-подсистеме с
другими программами и путями, и прогон краснел не из-за кода. Теперь все пять мест запуска
(прогон, доказательство, проба, храповик,why) идут через одну точку, которая берёт
bash.exeрядом сgit.exe; явный путь —AQK_BASH.vitalsназывает bash ненайденным,
если есть только заглушка. Отчёт с живого проекта: «через Git Bash все проходят». На ту же
ловушку наступали Claude Code и
Archon - Плавающий отказ
gates.sh(«отклонено: 1 из 29»).printf … | grep -qпри
set -o pipefail:grepвыходит на первом совпадении,printfполучает SIGPIPE, конвейер
возвращает 141 — и раздел README, который есть, объявлялся отсутствующим. Воспроизведено
100 из 100 под нагрузкой; поиск переведён на here-string - Проба не называет класс слепым, если подсадка сломала гейт, который до неё работал.
Сломанный гейт мог быть тем самым ловцом — вердикт «не смогли проверить», а не «никто не
ловит». Найдено пробой на самом комплекте: образец лёг на место общей библиотеки
kit/gates/_skip.sh, двенадцать гейтов вышли с кодом 2 — включая тот, что этот образец
ловит, — и проба назвала класс слепым
npx agent-quality-kit doctorv0.11.0
Выпуск про одно: проба впервые заработала на чужих проектах — и первым делом поймала нас
самих. До него probe запускалась у одного репозитория из семи; замер на десяти живых
проектах (chalk, execa, axios, dependency-cruiser, express, requests, click, flask, httpx,
black — от 377 до 6494 коммитов, с установленными зависимостями и объявленными СОБСТВЕННЫМИ
командами каждого) показал, что механика была недостижима для настоящего кода.
Пока её чинили, вскрылись четыре места, где наши же проверки молча зеленели там, где не
могли работать. Это тот самый класс, против которого написан весь стандарт.
Изменено — поведение, которое может покраснеть у вас
- Гейт, читающий историю, без репозитория выходит с кодом 2, а не 0. Раньше
commit-explains-itselfиtest-not-adjustedв каталоге без git отвечали «проверять нечего»
и код 0 — то есть «не смогли посмотреть» было неотличимо от «проверено и чисто». Договор
комплекта: 0 чисто, 1 находка, ВСЁ ОСТАЛЬНОЕ «не смогли». Если вы гоняете эти записи вне
репозитория, прогон станет красным — и это правда, а не регресс - Рецепты
ruffполучили-q --output-format=concise, рецептыeslint—
--no-config-lookupи исключение образцов. Причина в «Исправлено» ниже
Добавлено
- Проба работает на любом проекте. Образец подсаживается в КОПИЮ ПРОЕКТА, гейт запускается
в ней своей командой КАК ЕСТЬ — в неё больше ничего не подставляется. Раньше пробовать можно
было только команды, кончающиеся каталогом; замер на семи чужих репозиториях: у шести из семи
команды такие (xo,eslint lib/**/*.js,mocha --require…,pytest), и проба не
запускалась вовсе. Способ не выдуман — так двадцать лет устроено мутационное тестирование:
Stryker копирует проект во временный каталог, симлинкуетnode_modulesи гоняет родную
команду. Копируется РАБОЧЕЕ ДЕРЕВО, а не HEAD: комплект зовут из хука до коммита - Сухой прогон по чистой песочнице — без него «покраснел от подсадки» неотличимо от «был
красным и до неё». Гейт, красный до подсадки, и гейт, позеленевший от неё, из суждения
исключаются: засчитывать чужой долг за свою поимку нельзя - Проба видит JavaScript. Красные и зелёные образцы
.jsдля шести записей; семьи
расширений — образец.jsгодится файлам.mjsи.cjs. До этого в каталоге было 28
записей и НОЛЬ образцов на.js, то есть проба была слепа к самому распространённому языку
и к собственному коду комплекта - Цена пробы перестала расти файлами. Длительности берутся из сухого прогона, гейты идут от
быстрых к медленным, на первом красном — ранний выход, слишком медленные исключаются и
НАЗЫВАЮТСЯ ПОИМЁННО. Замер: 103 секунды вместо таймаута на 600 doctorназывает ЧЕЛОВЕКУ, сколько обещаний не сторожит машина. Числа считались и
печатались давно — но только в блокеcontext, который читает АГЕНТ. Единственный, кто
обязан помнить о непроверяемом обещании, был единственным, кому о нём не сообщали. Найдено не
нами: отчёт живого проекта
Исправлено
- Проверка, которая не может работать, зеленела. Подмена общей библиотеки
kit/gates/_skip.shдавала код 0: гейт печатал «command not found» и объявлял проект чистым.
Библиотеку подключает КАЖДАЯ запись каталога — одним испорченным файлом гасился весь набор
защит. Теперь библиотека ставит метку последней строкой (так ловится и обрыв файла на
середине), и все двенадцать подключений её проверяют - Родной рецепт выдавал НАШИ ЖЕ красные образцы за находки пользователя.
aqk addкладёт
их в проект — без нихproveничего не докажет, — и они существуют, чтобы быть
неправильными.ruffперешёл на многострочные блоки, а обход построчный и вырезать блок не
может. Итог: поставил запись при установленном ruff — получил вечно красный конвейер на
файлах, которые положили МЫ - Рецепты
eslintне запускались вовсе. ESLint 9+ требуетeslint.config.*; четыре записи
каталога на javascript и typescript у пользователя молча падали с кодом 2. Исключение теперь
на ВХОДЕ, а не фильтром вывода: ESLint 10 выкинул однострочные форматы из ядра, и подгонять
фильтр под формат каждого инструмента — гонка, которую не выиграть - Проба выдавала «не проверено» за «чисто». Итог считался одним числом: исходов три, веток
было две, иunknownмолча падал в «поймано всё». Проба, где ЕДИНСТВЕННАЯ запись вернула
«инструмент не установлен», печатала «каждый применимый класс кем-то ловится» - Проба врала о манифесте. При объявленных гейтах, которым некуда подставить каталог, она
говорила «гейтов не объявлено, сначала aqk add» — и отправляла заводить то, что уже заведено - Проба завышала число втрое. Считала класс × файл: шесть классов на трёх горячих файлах
превращались в «18 непокрытых». Считали события, а называли их сущностями — ровно тот приём,
который ловим у других complexity-limitбыл вдвое слеп к JavaScript. Мерил вложенность делением отступа на
четыре, а в JS отступ — два пробела: шесть уровней давали «три» и проходили предел молча.
Дефект был невидим, пока в каталоге не было ни одного образца на.js- §10
PROJECT.mdутверждал, что соседи не про готовность к работе агентов. Неправда:
Factory Agent Readiness (9 столпов, 5 ступеней, 100+ сигналов) иkodustech/agent-readiness
(109 звёзд, 39 проверок) — ровно про неё. Соседи названы поимённо и с размером - Числа в обещаниях разошлись с фактом. Пакет: обещано «230 КБ» в трёх живых местах, на
деле 574. Методички: «13 файлов, 4312 строк» против 14 и 4663
Границы, названные вслух
- Обещание вне точки входа не проверяет НИЧТО, и стандарт об этом даже не сообщал.
Расширять область нельзя дёшево: распознаватель ловит любой выделенный пункт списка и на
связанных документах утонет в ложных срабатываниях - Свойства работающей системы — скорость, память, поведение под нагрузкой — чтением файлов
не проверяются вовсе. Это граница замысла, а не пробел - Правило со сторожем-человеком не сторожит никто. В нашем собственном своде так помечено
12 правил из 14
npx agent-quality-kit doctorv0.10.1
Выпуск исправлений правильности. Все четыре дефекта — одно правило, разные лица:
«не знаем» обязано иметь собственное слово в выводе. Как только у него нет своей ветки,
оно молча приклеивается к соседней — и почти всегда к «всё хорошо». Каждый дефект подтверждён
опытом до правки и повторён после неё в чистой копии.
Исправлено
- Сбой инструмента засчитывался как доказательство.
proveсчитал находкой ЛЮБОЙ ненулевой
код на красном образце. Опыт: гейт, который ВИСНЕТ на красном образце и молчит на зелёном,
получал вердиктproven: 1, ok: true— то есть зависший гейт объявлялся ловящим брак, и это
считало ступень AQK-2. Заведёнtool/lib/execution.mjs: три исхода запуска — чисто, находка,
сбой инструмента с названной причиной (таймаут, сигнал, ошибка запуска, неожиданный код).
Знание о кодах живёт в адаптере рядом с инструментом, потому что общего правила нет:
замер показал, что уvultureнаходка это 3, а 1 и 2 — ошибки; уpylintнаходка идёт
битовой маской, а 32 означает ошибку вызова. Правило «1 находка, 2+ сбой» переврало бы обоих
в обе стороны - Один доказанный гейт покрывал любое число недоказанных. Вердикт был
broken === 0 && proven > 0. Теперь сбой арбитра отнимает ступень, а законная недоказуемость
(нет образцов, нет программы на этой машине, стоит рецепт под другой язык) — нет: иначе
уровень зависел бы от того, что установлено - Проверка защиты сама создавала себе доказательство.
protection-not-removedпри
отсутствии снимка создавал его и выходил с нулём. Опыт: убрать гейт, удалить снимок и уйти
вперёд так, чтобы удаление оказалось глубже выкладки конвейера, — свидетель (история git)
слеп, и проверка записывала уже ослабленный набор новым эталоном. Храповик крутился назад.
Теперь проверка только сравнивает; снимок пишет установка (aqk add); отсутствующий и
отставший снимок — красное - Расписка за диф считала команду выводом.
evidenceбрал пути из команды И вывода разом:
молчащий гейт делал «названным» любой файл из строки запуска. Так «доказывалась» каждая правка
самих проверок. Теперь «названо» — только вывод, а имена из команды дают «обойдено молча»,
включая отдельный файл, который прежде падал в «никто не смотрел» - У пробы пять состояний, а веток было три.
off(выключена в манифесте) иunknown
(счётчик коммитов не взять либо непонятое значение поля) печатались как «в проверенных местах
каждый применимый класс кто-то ловит». Блок состояния читает машина, и она приняла бы это за
разрешение
Изменено
- Комплект сам исполняет
test-not-adjusted. Мы советовали записи, которых сами не держали.
Замер развёл три случая: эту запись поставили (на нашем коде она проходит);swallowed-error
на нашем коде чист, но требуетeslint— отдельное решение;no-print-in-prodдаёт 216
находок, и все они наш собственный вывод в терминал — его же README называет этот класс ложным
npx agent-quality-kit doctor