Quality Gates Reference (Русский)
Инвентаризация проверок (~90 скриптов)
Заголовок раздела «Инвентаризация проверок (~90 скриптов)»Скрипты находятся в scripts/check/ (проверки политик) и scripts/quality/ (механизм трещотки).
Единственным источником истины для CI является .github/workflows/ci.yml.
Ускоренный путь для PR в релизные ветки (quality.yml)
Заголовок раздела «Ускоренный путь для PR в релизные ветки (quality.yml)».github/workflows/quality.yml запускается для PR, нацеленных на release/**. Он позволяет
не задерживать работу в ветках участников благодаря быстрым проверкам с фильтрацией по путям,
а также предоставляет один рекомендательный сигнал производственной сборки для изменений кода:
| Задача | Область действия | Блокировка |
|---|---|---|
Build (advisory) |
Не черновые PR с кодом и ветки очереди Mergify; Node 24, npm-ci-retry, check:node-runtime, npm run build с OMNIROUTE_USE_TURBOPACK=1; артефакт не загружается, поскольку ни одна последующая задача контроля качества его не использует |
Рекомендательная (continue-on-error: true; удалить после одной недели стабильных запусков для релизных PR) |
Docs Gates (fast-path) |
PR с документацией/кодом; ссылки в документации API и docs-all | Да |
Fast Quality Gates |
PR с кодом; статические проверки, проверка типов, проверка типов панели управления, затронутые модульные тесты | Да |
Forgotten sibling tests |
PR с кодом; отслеживание изменённых модулей до статических потребителей и потенциальных соседних тестов; пути через barrel-экспорты и динамические импорты выводятся как рекомендательная диагностика с указанными исключениями из списка разрешений | Рекомендательная |
Vitest (fast-path) |
PR с кодом; быстрый набор тестов vitest | Да |
Unit Tests fast-path |
PR с кодом; набор модульных тестов в 4 шардах | Да |
No new ESLint warnings |
PR с кодом; проверка линтинга с учётом подавлений | Да для PR из этого репозитория, рекомендательная для форков |
Merge integrity (changelog + generated skills) |
Не черновые PR; синхронизация журнала изменений и сгенерированных навыков | Да для PR из этого репозитория, рекомендательная для форков |
Отчёт о забытых соседних тестах
Заголовок раздела «Отчёт о забытых соседних тестах»npm run check:forgotten-sibling-tests повторно использует механизм разрешения импортов, лежащий в основе карты влияния на тесты.
Для каждого изменённого производственного модуля он выводит детерминированные цепочки
изменённый модуль/символ -> статический потребитель -> потенциальный соседний тест, если потенциальный
тест отсутствует в изменениях pull request. Сводка Markdown и результат JSON сохраняются как
артефакт рабочего процесса forgotten-sibling-tests для калибровки перед возможным переводом проверки в блокирующий режим.
Barrel-реэкспорты и динамические импорты используются только для диагностики разрешения; они никогда не создают
блокирующее замечание. Проверенные исключения находятся в
config/quality/forgotten-sibling-allowlist.json. Каждая запись должна указывать потребителя и потенциальный
тест, содержать конкретное обоснование и ссылку на задачу GitHub или pull request. Некорректные записи приводят
к блокирующему отказу. Исключения не могут подавить удаление потенциального теста или изменение, добавляющее .skip/.todo;
ослабление утверждений и другие способы маскировки остаются в зоне ответственности независимо блокирующей
проверки check:test-masking.
Задача: lint
Заголовок раздела «Задача: lint»Запускается для каждого PR в main. При сбое блокирует слияние.
Скрипт (npm run ...) |
Проверяет | Блокирующий |
|---|---|---|
check:node-runtime |
Версия Node.js находится в поддерживаемом диапазоне | Да |
check:cycles |
Циклические импорты во всех модулях src/ + open-sse/ |
Да |
check:route-validation:t06 |
Наличие схем Zod во всех маршрутах (политика уровня 6) | Да |
check:any-budget:t11 |
Количество @ts-expect-error // any не превышает установленный лимит (турникет уровня 11) |
Да |
check:provider-consistency |
Для каждого провайдера в providers.ts существует соответствующая запись в providerRegistry.ts (и наоборот, в пределах списка разрешений) |
Да |
check:model-lifecycle |
Три поддерживаемые вручную таблицы маршрутизации остаются согласованными с зафиксированным в репозитории снимком жизненного цикла (#11503): FITNESS_TABLE (taskFitness.ts) не оценивает ни один выведенный из эксплуатации идентификатор, который может маршрутизировать REGISTRY; каждая цель BUILT_IN_ALIASES присутствует в REGISTRY и отсутствует в снимке выведенных из эксплуатации идентификаторов; каждый выведенный из эксплуатации идентификатор, всё ещё находящийся в REGISTRY, перенаправляется или указан в allowedRetiredInCatalog; ни один источник или цель DEFAULT_DEGRADATION_MAP не помечены в этом снимке как выведенные из эксплуатации. Это не доказывает, что модель в настоящее время обслуживается действующим внешним сервисом. Проверка выполняется автономно — путём сравнения с config/quality/model-lifecycle.json, который обновляется вручную с помощью npm run quality:refresh-model-lifecycle (требуется сеть; не подключено к CI). allowedRetiredInCatalog — это механизм постепенного сокращения списка: добавляйте запись только при наличии задачи для её отслеживания. |
Да |
check:fetch-targets |
Каждый вызов fetch("/api/...") в клиентской части src/ разрешается в реально существующий route.ts |
Да |
check:deps |
Все зависимости, устанавливаемые через npm install, во всех файлах package.json репозитория присутствуют в dependency-allowlist.json; новые пакеты с незакреплёнными версиями или подозрительными именами, имитирующими известные пакеты, помечаются |
Да |
audit:deps |
npm audit (корневой проект + Electron) — отсутствие предупреждений высокой/критической степени опасности (частично дублирует OSV-проверку check:vuln-ratchet; см. список задач по рационализации) |
Да |
check:lockfile |
Целостность package-lock.json — реестр HTTPS, хеши целостности, отсутствие переопределений хостов |
Да |
check:licenses |
Список разрешённых лицензий SPDX для производственных зависимостей | Да |
check:tracked-artifacts |
Отсутствие артефактов сборки / зафиксированных символических ссылок node_modules (также запускается в husky pre-commit; pre-push намеренно сделан лёгким — #6716) |
Да |
check:ai-attribution |
Отсутствие трейлера Co-Authored-By от ИИ/бота или примечания о генерации с помощью ИИ в коммитах, заголовке или описании PR — жёсткое правило №16 (в цикле быстрых проверок quality.yml для PR→release/** — читает полезную нагрузку события и ничего не делает вне PR — и отдельный шаг только для PR в проверке lint файла ci.yml для PR→main; также хук husky commit-msg; соавторы-люди разрешены; #14436) |
|
check:vitest-exclusions |
Каждое исключение Vitest содержит ссылку на отслеживаемую задачу и присутствует в config/quality/vitest-exclusions.json (#13204) |
Да |
check:file-size |
Ни один исходный файл не превышает ограничение для соответствующего расширения (храповик: зафиксированные крупные файлы в списке frozen) |
Да |
check:error-helper |
Ответы с ошибками в исполнителях/обработчиках используют buildErrorBody() / sanitizeErrorMessage() (жёсткое правило №12) |
Да |
check:migration-numbering |
SQL-файлы миграций имеют последовательную нумерацию, без пропусков и дубликатов | Да |
check:public-creds |
Отсутствуют литеральные значения OAuth client_id/client_secret и веб-ключи Firebase за пределами publicCreds.ts (жёсткое правило №11) |
Да |
check:db-rules |
Отсутствует необработанный SQL за пределами модулей src/lib/db/; отсутствуют импорты из barrel-файла localDb.ts (жёсткие правила №2/№5) |
Да |
check:known-symbols |
Исполнители провайдеров, стратегии маршрутизации и трансляторы, зарегистрированные в соответствующих таблицах диспетчеризации, соответствуют файлам на диске — нет потерянных или необъявленных символов | Да |
check:route-guard-membership |
Каждый маршрут, запускающий дочерний процесс, классифицируется функцией isLocalOnlyPath() (жёсткие правила №15/№17) |
Да |
check:test-discovery |
Каждый файл *.test.ts / *.spec.ts в репозитории обнаруживается хотя бы одним средством запуска тестов (храповый механизм: список потерянных тестов в test-discovery-baseline.json может только сокращаться) |
Да |
check:agent-skills-sync |
Сгенерированные артефакты agent-skills соответствуют исходному каталогу (без расхождений) | |
check:provider-asset-provenance |
Для логотипов/ресурсов провайдеров зафиксирована информация о происхождении | |
lint:json |
Файлы конфигурации JSON корректно разбираются и соответствуют правилам линтинга репозитория | |
typecheck:core |
Компиляция TypeScript без ошибок (только рекомендательные предупреждения) | Да |
typecheck:noimplicit:core |
Строгий режим noImplicitAny — задел на будущее; многие существующие места вызова всё ещё требуют аннотаций |
Рекомендательный (continue-on-error: true) |
check:dashboard-typecheck |
tsc, ограниченный областью src/app/(dashboard)/** (#7033), — подготовленный список разрешённых 27 файлов в typecheck:core не включает ни одного dashboard TSX, а next build также никогда не проверяет их типы (next.config.mjs задаёт ignoreBuildErrors: true), поэтому регрессии с необъявленными идентификаторами в них (#6625/#6909) были невидимы для CI. Выполняется сравнение с зафиксированной базовой линией количества ошибок по каждому файлу и коду TS (config/quality/dashboard-typecheck-baseline.json, с той же схемой контроля устаревания, что и в check:known-symbols): проверка завершается неудачно только при появлении НОВЫХ ошибок сверх базового количества; уменьшайте базовую линию с помощью --update после исправления существующей ошибки. |
Да |
Задание: quality-gate
Заголовок раздела «Задание: quality-gate»Запускается после test-coverage. При неудачном выполнении блокирует слияние.
| Скрипт | Что проверяет | Блокирующий |
|---|---|---|
quality:collect |
Создаёт quality-metrics.json (количество предупреждений ESLint, покрытие из объединённого отчёта по сегментам) |
Да (предшествует ratchet) |
quality:ratchet |
Ни одна метрика в quality-baseline.json не ухудшилась (предупреждения ESLint ≤ базового значения; покрытие ≥ базового значения) |
Да |
check:duplication |
Дублирование кода (jscpd@4) не превышает базовое значение в quality-baseline.json |
Да |
check:complexity |
Цикломатическая сложность на уровне файлов не превышает установленный предел (встроенные правила ESLint complexity + max-lines-per-function) |
Да |
check:cognitive-complexity |
Ratchet когнитивной сложности (eslint-plugin-sonarjs) — отдельный проход ESLint; CI запускает обе проверки вместе как единый шаг check:complexity-ratchets |
Да |
check:dead-code |
Ratchet неиспользуемых экспортов / файлов (knip) не ухудшается относительно базового значения | Да |
check:compression-budget |
Бюджет теста производительности сжатия — минимальные пороги экономии токенов для каждого движка не должны снижаться | Да |
check:type-coverage |
Ratchet доли типизированного кода (type-coverage) не ухудшается; в значительной степени включает в себя typecheck:noimplicit:core |
Да |
check:codeql-ratchet |
Количество открытых предупреждений CodeQL не увеличивается (данные получаются через gh api; корректный пропуск без токена) — периодичность обновления и ручной запуск: см. «CodeQL ratchet» ниже |
Да |
Задание: quality-extended
Заголовок раздела «Задание: quality-extended»Всё задание носит рекомендательный характер (continue-on-error: true). Ratchet-проверки на базе npm выполняются
полноценно; внешние сканеры устанавливаются через gh release download и самостоятельно пропускают проверку (exit 0),
если бинарный файл по-прежнему отсутствует.
| Скрипт | Что проверяет | Блокирующий |
|---|---|---|
check:circular-deps |
Отсутствие циклических зависимостей (dpdm) | Рекомендательный |
check:bundle-size |
Размер бандла не превышает установленный предел | Рекомендательный |
check:secrets |
Поиск секретов (gitleaks) — пропускается, если бинарный файл отсутствует | Рекомендательный |
check:vuln-ratchet |
Уязвимости зависимостей (osv-scanner) не увеличиваются — пропускается, если бинарный файл отсутствует | Рекомендательный |
check:workflows |
Линтинг рабочих процессов (actionlint + zizmor) — пропускается, если бинарные файлы отсутствуют | Рекомендательный |
check:openapi-breaking |
Критические изменения публичного контракта API (openapi.yaml) относительно базовой ветки (oasdiff) — выводит openapiBreaking=N; пропускается, если oasdiff отсутствует или базовую спецификацию невозможно получить |
Рекомендательный |
Задание: docs-sync-strict
Заголовок раздела «Задание: docs-sync-strict»Запускается для каждого PR в main. При сбое блокирует слияние.
| Скрипт | Что проверяет | Блокирующая проверка |
|---|---|---|
check:docs-all |
Мета-проверка, последовательно запускающая 6 приведённых ниже проверок | Да |
↳ check:docs-sync |
Согласованность версий в CHANGELOG / OpenAPI / llm.txt | Да |
↳ check:docs-counts |
Числовые данные в тексте (количество провайдеров, миграций и т. д.) находятся в пределах допустимого окна относительно фактических значений | Да |
↳ check:env-doc-sync |
Каждая переменная окружения из .env.example задокументирована в таблице документации, и наоборот |
Да |
↳ check:deprecated-versions |
В документации отсутствуют строки с устаревшими версиями | Да |
↳ check:doc-links |
Внутренние markdown-ссылки в документации указывают на существующие файлы (в формате [текст]/(путь)) |
Да |
↳ check:fabricated-docs |
Упомянутые в документации маршруты, переменные окружения, команды CLI, имена хуков и пути к файлам существуют в кодовой базе. Строгая проверка с --strict; без флага ошибка не блокирует выполнение. |
Да (с --strict в CI) |
check:cli-i18n |
Строки команд CLI присутствуют во всех файлах локалей i18n | Да |
check:openapi-coverage |
Спецификация OpenAPI охватывает как минимум пороговое количество реальных маршрутов | Да |
check:openapi-security-tiers |
Аннотации уровней безопасности в openapi.yaml согласованы с классификациями в routeGuard.ts |
Рекомендательная |
check:openapi-routes |
Каждый путь в openapi.yaml соответствует реальному route.ts (защита от галлюцинаций) |
Да |
check:docs-symbols |
Каждая ссылка /api/... в docs/**/*.md соответствует реальному route.ts (защита от галлюцинаций) |
Да |
i18n translation drift |
Непереведённые ключи в файлах локалей i18n — только предупреждение | Рекомендательная |
Задание: i18n-ui-coverage
Заголовок раздела «Задание: i18n-ui-coverage»| Скрипт | Что проверяет | Блокирующая проверка |
|---|---|---|
check-ui-keys-coverage (встроенный) |
Покрытие ключей i18n интерфейса составляет ≥ 65% | Да |
check-ui-value-drift (встроенный) |
После изменения английского значения не остаётся устаревшего перевода | Да |
check-new-key-coverage (встроенный) |
Новый английский ключ переведён во всех локалях — маркер __MISSING__: недопустим |
Да |
check-translation-ratio |
Доля реальных переводов для каждой локали (листья, идентичные английским / содержащие заполнители / отсутствующие вне списка исключений) не должна превышать config/quality/i18n-translation-baseline.json + допустимый запас |
Рекомендательная |
Требуется fetch-depth: 0 — проверка расхождения значений сравнивает en.json с базой слияния.
check-ui-value-drift — проверка устаревших переводов
Заголовок раздела «check-ui-value-drift — проверка устаревших переводов»Выявляет единственную регрессию i18n, которую другие проверки не способны обнаружить структурно: английское значение переписывается, а переводы, созданные на основе предыдущего английского текста, остаются без изменений, поэтому пользователи неанглоязычных локалей продолжают читать уверенно сформулированный, но теперь уже неверный текст.
Это действительно попало в релиз. oauthModal.googleOAuthWarning был переписан при добавлении
помощника входа Antigravity (#5203); в 39 из 43 локалей остался текст, предлагавший операторам
«скопировать полный URL-адрес и вставить его ниже» — процесс, который невозможно завершить
для этого провайдера. Проблема оставалась незамеченной до #8463, потому что:
sync-ui-keysдобавляет только отсутствующие ключи и никогда не обновляет устаревшие;check-ui-keys-coverageучитывает наличие ключа, поэтому устаревший перевод считается покрытым;check-translation-driftотслеживает зеркальные копии документацииdocs/i18n/<locale>/**.md— файлыsrc/i18n/messages/*.jsonон не читает. Блокирует выполнение в заданииdocs-sync-strictпосле повторной синхронизации 2026-09: измените основной документ →npm run i18n:run -- --files=<doc>(на уровне раздела, с низкими затратами).
Учитывает diff, а не опирается на базовый файл. Проверка сравнивает en.json в базе слияния
с рабочим деревом; для каждого ключа, английское значение которого изменилось, локаль,
по-прежнему содержащая неизменённый перевод, считается устаревшей. Это намеренно
фиксирует ранее накопленный долг — по diff невозможно определить, из какой старой
английской строки был получен давно существующий перевод, поэтому проверка оценивает
только то, чего касается текущее изменение. Альтернатива (базовый файл с хешем для каждого
ключа) потребовала бы генерируемый файл размером около 600 КБ, что в 3 раза больше
крупнейшего существующего базового файла и приводило бы к изменениям при каждом i18n PR.
Есть два способа пройти проверку:
- обновить затронутые переводы или
- задать для них значение
__MISSING__:<новый английский текст>— тогда во время выполнения будет возвращаться исправленный английский текст (src/i18n/request.ts::deepMergeFallback, #7258), а ключ попадёт в очередь на перевод.
Если изменился смысл строки, предпочтительнее переименовать ключ: новый ключ не может унаследовать устаревший перевод. Этот подход использовался в #8463.
npm run i18n:check-value-drift # строгий режим (используется в CI)npm run i18n:check-value-drift:warn # только отчётBASE_REF=origin/release/vX.Y.Z npm run i18n:check-value-driftЗавершается с кодом 0 и сообщением SKIP reason=base-unresolved, если базовый каталог
невозможно прочитать (поверхностный клон без базовой ссылки), аналогично
check-openapi-breaking.
Задание: i18n
Заголовок раздела «Задание: i18n»Полная матрица проверки i18n (по одному заданию на локаль). Всё задание носит рекомендательный характер.
| Скрипт | Что проверяет | Блокирует |
|---|---|---|
validate_translation.py quick |
Полноту перевода для каждой локали | Нет (continue-on-error: true для всего задания) |
Задание: pr-test-policy
Заголовок раздела «Задание: pr-test-policy»Выполняется только для запросов на включение изменений.
| Скрипт | Что проверяет | Блокирует |
|---|---|---|
check:pr-test-policy |
PR, изменяющие рабочий код в src/, open-sse/, electron/ или bin/, должны добавлять или обновлять тесты (жёсткое правило № 8) |
Да |
check:test-masking |
Изменённые тестовые файлы не уменьшают общее количество проверок и не добавляют тавтологии assert.ok(true) |
Да |
check:pr-evidence |
Текст PR содержит сведения о тестировании/VPS для изменения (автоматизирует жёсткое правило № 18 поиском по тексту PR — ненадёжно, см. Backlog) | Да |
Задание: test-vitest
Заголовок раздела «Задание: test-vitest»Выполняется после build. При ошибке блокирует слияние.
| Набор | Что проверяет | Блокирует |
|---|---|---|
test:vitest |
MCP-сервер (110 инструментов), autoCombo, кеш — vitest | Да |
test:vitest:ui |
Тесты компонентов интерфейса — vitest | Да — ранее существовавшие сбои явно исключены в vitest.config.ts; новые сбои приводят к ошибке задания |
Ночные рабочие процессы (по расписанию, рекомендательные)
Заголовок раздела «Ночные рабочие процессы (по расписанию, рекомендательные)»Они запускаются по расписанию cron (а также через workflow_dispatch) и никогда не
выполняются для PR. Все они носят рекомендательный характер.
| Рабочий процесс | Что проверяет | Блокирует |
|---|---|---|
nightly-property |
Тесты свойств fast-check со случайным начальным значением и большим количеством запусков | Нет |
nightly-resilience |
Ограничение роста кучи, хаотическое внедрение сбоев, нагрузочное/длительное тестирование k6 | Нет |
nightly-llm-security |
Защиту promptfoo от инъекций (режим блокировки) и проверки garak (пропускаются без секрета провайдера) | Нет |
nightly-schemathesis |
Фаззинг контракта OpenAPI (schemathesis) для работающего OmniRoute с использованием docs/openapi.yaml — выявляет нарушения спецификации / необработанные ошибки 500 (этап 8 B.4) |
Нет |
nightly-mutation |
Показатель мутационного тестирования Stryker для быстрого набора модульных тестов — выжившие мутанты выявляют слабые проверки | Нет |
nightly-compat |
Матрицу совместимости движка Node для поддерживаемых диапазонов engines.node |
Нет |
Фаза ускорения (2026-08-30 → v4.0 LTS): все базовые пороги ослаблены на 20%
Заголовок раздела «Фаза ускорения (2026-08-30 → v4.0 LTS): все базовые пороги ослаблены на 20%»Решение владельца (2026-08-30): до модульной переработки в v4.0 скорость выпуска важнее,
чем сдерживание технического долга. Все числовые базовые пороги ratchet-проверок были ослаблены на 20% за один
аудируемый проход, а фаза объявлена в config/quality/quality-baseline.json:
"_policy": { "phase": "velocity", "since": "2026-08-30", "until": "4.0.0", "relaxPct": 20, "requireTighten": false }| Что изменилось | Где |
|---|---|
metrics.*.value — показатели, где меньше — лучше, ×1.2; проценты, где больше — лучше, ÷1.2 (минимальное покрытие сохранено на уровне 60, eslintErrors остаётся 0, eslintWarnings 0 → 20% от зафиксированного числа подавлений) |
quality-baseline.json (в примечании _relax_velocity_2026_08_30 перечислены все значения до → после) |
count ×1.2 / percentage ×1.2 |
complexity-baseline.json, duplication-baseline.json |
cap, testCap, ограничение числа строк для каждого frozen[*] / testFrozen[*] ×1.2 |
file-size-baseline.json |
| количество по файлам / по TS-коду ×1.2 | api-typecheck-baseline.json, dashboard-typecheck-baseline.json, open-sse-typecheck-baseline.json |
THRESHOLD 36 → 30 |
scripts/check/check-openapi-coverage.mjs |
--require-tighten носит рекомендательный характер, пока _policy.requireTighten === false |
scripts/quality/check-quality-ratchet.mjs |
ночная задача bank-ratchet-shrinks приостановлена (иначе она зафиксировала бы измеренное снижение и свела на нет запас) |
.github/workflows/nightly-release-green.yml |
Списки разрешений (eslint-suppressions.json, test-masking-allowlist.json, test-discovery-baseline.json,
…) не являются бюджетами и не были изменены. Политики проверок с результатом «пройдено/не пройдено» (секреты, правила SQL,
контракт документации и окружения, паритет i18n, модульные тесты) не изменились — непройденный тест по-прежнему считается непройденным.
Инструменты
npm run quality:relax-baselines -- --pct 20 --note velocity_YYYY_MM_DD [--dry-run]— однократное ослабление (scripts/quality/relax-baselines.mjs); повторный запуск с тем же примечанием отклоняется.npm run quality:headroom [-- --only deadExports,fileSize] [--json out.json --md out.md]— измеряет каждый числовой порог так же, как CI, и выводит оставшийся запас для каждого порога (scripts/quality/baseline-headroom.mjs). Ночная задачаbaseline-headroomпубликует таблицу в постоянно обновляемой задаче 📈 Запас базовых порогов (фаза ускорения) и добавляет меткуheadroom-alert, когда какой-либо показатель оказывается в пределах 10% от своего предела или уже превышает его. Эта задача служит ранним предупреждением: если бюджет исчерпывается за несколько дней, значит, ослабление расходуется несколькими PR, а не всей командой — смотрите примечания_rebaseline_*соответствующей проверки.
Режим нового кода (Clean-as-You-Code) — с 2026-08-30, только для ускоренного пути PR
При событиях pull_request файл quality.yml передаёт --base-ref <PR base SHA> в check:file-size,
check:complexity-ratchets и check:dead-code. В этом режиме проверка сравнивает HEAD с
базой слияния только для файлов, затронутых PR (scripts/check/newCodeMode.mjs:
база слияния материализуется во временном git worktree, ESLint/knip запускаются там и на HEAD, после чего
вычисляется разница показателей по файлам):
- блокирующая проверка — PR добавил нарушения цикломатической/когнитивной сложности или мёртвые экспорты в изменённых им файлах
(
complexityNewCode=,cognitiveComplexityNewCode=,deadExportsNewCode=в журнале); - рекомендательная проверка — глобальное итоговое значение относительно зафиксированного базового порога. Унаследованное отклонение никогда не делает проверку непричастного PR красной; отклонение повторно фиксируется при сверке релиза и отслеживается задачей контроля запаса.
Запуски workflow_dispatch, проверка release-green и ночная задача контроля запаса не имеют базовой версии PR
и продолжают использовать абсолютное (глобальное) сравнение. Покрытие, дублирование и покрытие типами пока остаются глобальными
(их инструменты не позволяют дёшево получить разницу по файлам) — они являются кандидатами на такой же подход.
Завершение фазы в v4.0 (LTS = строже, чем раньше, а не «возврат к норме»)
- На чистой вершине ветки
release/v4.0.0: для протокола выполнитеnpm run quality:headroom --json, затемnpm run quality:ratchet -- --update,check:file-size --update,check:complexity-ratchets --update,check:dead-code --update, а также--updateдля каждого гейта проверки типов — все базовые значения снизятся до измеренных. - Удалите
_policyизquality-baseline.json(это повторно активирует--require-tightenи ночное накопление), восстановитеTHRESHOLD = 36(или выше) вcheck-openapi-coverage.mjs. - Ужесточите ограничения сверх измеренных значений там, где модульность принесла результат: верните
capразмера файла к 1000 (или 800), повысьте минимальные пороги покрытия на 5, установите 0 неиспользуемых экспортов для переведённых на модульную структуру пакетов.
Базовый уровень храповика (quality-baseline.json)
Заголовок раздела «Базовый уровень храповика (quality-baseline.json)»Механизм храповика (scripts/quality/check-quality-ratchet.mjs) считывает quality-baseline.json
и сравнивает его со свежесобранным quality-metrics.json. Если любая метрика ухудшается
больше, чем допускает её эпсилон, сборка завершается с ошибкой.
Текущие отслеживаемые метрики:
| Метрика | Направление | Значение |
|---|---|---|
eslintWarnings |
down |
Количество предупреждений ESLint не должно расти |
coverage.statements |
up |
Покрытие операторов не должно снижаться |
coverage.lines |
up |
Покрытие строк не должно снижаться |
coverage.functions |
up |
Покрытие функций не должно снижаться |
coverage.branches |
up |
Покрытие ветвей не должно снижаться |
Чтобы обновить базовый уровень после фактического улучшения:
npm run quality:ratchet -- --updategit add quality-baseline.jsonФлаг --update записывает текущие измеренные значения в quality-baseline.json.
Зафиксируйте этот файл вместе с изменением, улучшившим метрику. PR, который улучшает
метрику без обновления базового уровня, будет обнаружен с помощью --require-tighten (Фаза 6A.5,
реализация ожидается).
Храповик CodeQL: периодичность обновления и ручной запуск
Заголовок раздела «Храповик CodeQL: периодичность обновления и ручной запуск»check:codeql-ratchet считывает состояние репозитория, обновляемое по расписанию, а не для каждого PR.
gh api repos/diegosouzapw/OmniRoute/code-scanning/default-setup сообщает
state: configured, schedule: weekly: это сканирование GitHub с настройками по умолчанию, а не анализ
при каждой отправке изменений. Следствие: после слияния PR, ИСПРАВЛЯЮЩЕГО предупреждения, храповик продолжает считывать
старое, более высокое значение до следующего запуска сканирования по расписанию — поэтому он сообщает о регрессии
в каждом открытом PR, включая последующие PR для исправляющего PR, пока результаты сканирования не обновятся.
Ручное обновление: gh workflow run codeql.yml --ref release/vX.Y.Z повторно запускает
анализ и в течение нескольких минут повторно публикует предупреждения. Сначала прочитайте .github/workflows/codeql.yml
— в его заголовке объясняется, что используется только workflow_dispatch, поскольку он конфликтует с
«настройками по умолчанию» GitHub (CodeQL analyses from advanced configurations cannot be processed when the default setup is enabled). Для восстановления триггеров push/pull_request/
schedule сначала требуется действие владельца: Настройки → Безопасность кода →
CodeQL: По умолчанию → Расширенная. Не добавляйте триггер schedule: без этого переключения — он
будет приводить только к неудачным запускам.
Ужесточите базовый уровень после уменьшения количества — node scripts/check/check-codeql-ratchet.mjs --update записывает новое измеренное количество в quality-baseline.json →
metrics.codeqlAlerts.value, чтобы храповик не допускал незаметной регрессии обратно
до старого предельного значения. Практический пример (2026-09-02/03): PR #12502 исправил 7 реальных предупреждений
(13 → 6 измеренных открытых); PR #12530 ужесточил зафиксированный базовый уровень с 11 до 6 для соответствия; затем
оставшиеся 6 были отклонены с отдельным обоснованием для каждого предупреждения, в результате чего открытых предупреждений стало 0.
Решение об отклонении принимает оператор (Жёсткое правило #14) — никогда не отклоняйте предупреждение CodeQL,
не указав техническое обоснование в комментарии к отклонению: won't fix для
требования вышестоящего протокола, used in tests для тестовой фикстуры, false positive
для санитайзера, который CodeQL не может обнаружить (прецедент: docs/security/ERROR_SANITIZATION.md).
Политика повторных запусков тестов (WS5.4, v3.8.49)
Заголовок раздела «Политика повторных запусков тестов (WS5.4, v3.8.49)»Повторные запуски настраиваются отдельно для каждого раннера, а не глобально для всех — глобальный повторный запуск превращает реальные регрессии в незаметные нестабильности:
| Раннер | Политика | Почему |
|---|---|---|
| Playwright (e2e) | retries: 1 только в CI, с trace: on-first-retry |
Временные параметры браузера/сети действительно недетерминированы; один повторный запуск с трассировкой превращает нестабильность в диагностируемый артефакт |
| Vitest | БЕЗ глобального повторного запуска. Для подтверждённо нестабильного теста повторный запуск задаётся явно на уровне теста (виден в diff и проверяется в PR) | Список изолированных тестов остаётся в репозитории и никогда не становится непрозрачным |
| node:test (unit) | БЕЗ повторных запусков, никогда | Нестабильный модульный тест — это ошибка в тесте: исправьте её, а не запускайте тест заново |
Целевые SLO после появления телеметрии нестабильностей (WS5.2/5.3): частота нестабильности <1% для каждого теста (порог «исправить сейчас»), доля успешных выполнений для каждого пайплайна ≥95%. Это отраслевые ориентиры — их следует откалибровать по нашим собственным измерениям.
Дрейф ограничителей на уровне релиза (WS5.5, v3.8.49)
Заголовок раздела «Дрейф ограничителей на уровне релиза (WS5.5, v3.8.49)»Когда ограничитель (размера файла, сложности, предупреждений eslint) регрессирует на ЧИСТОЙ вершине релизной ветки — то есть регрессия возникает из-за КОМБИНАЦИИ слияний и ни один отдельный PR не воспроизводит её в собственной ветке, — исправление выполняет капитан релиза, однократно, в релизной ветке: предпочтительно выделить код или провести рефакторинг; обновлять базовый уровень можно только с документированным обоснованием. Никогда не перекладывайте дрейф, вызванный комбинацией изменений, на PR участника и никогда не обновляйте базовый уровень отдельно для каждого PR (это скрывает реальные регрессии). Сначала определите источник: воспроизведите ошибку на чистой вершине в проверочном worktree, прежде чем предполагать, что её вызвал ваш PR.
Фиксация снижений ограничителей — движение вниз (#8584)
Заголовок раздела «Фиксация снижений ограничителей — движение вниз (#8584)»Автоматизирована лишь половина механизма ограничителей, причём не та половина, которая нужна. Повышение предела — это ручное редактирование JSON, занимающее десять секунд и позволяющее быстрее всего разблокировать красный PR. Понижение требует, чтобы кто-то запустил --update и зафиксировал результат, — а до появления задания bank-ratchet-shrinks ни один рабочий процесс этого не делал. Измеренные последствия (2026-07-25): 18 замороженных файлов уже достигли или опустились ниже предела в 800 строк для новых файлов, худший случай превышает актуальное значение в 132 раза (src/shared/validation/schemas.ts: 19 строк при установленном пределе 2 523); потолок сложности вырос с 1794 → 2169 примерно за 37 заметок об обновлении базового уровня и снизился ровно один раз (−1); фраза «снизить через --update в следующем цикле» была записана 31 раз, а выполнено это было один раз. Предел, сохраняющийся дольше, чем код, из-за которого он появился, незаметно превращает каждую завершённую декомпозицию в разрешение на рост для следующего разработчика, изменяющего файл.
nightly-release-green.yml → задание bank-ratchet-shrinks замыкает этот цикл:
| Запуск | schedule (3 раза в день) + workflow_dispatch — намеренно не push |
| Измеряет | старшую ветку release/vX.Y.Z, с тем же разрешением и защитой от внедрения, что и release-green |
| Записывает | check:file-size --update и check:complexity-ratchets --update (оба по своей реализации допускают только снижение) |
| Проверяет | npm run check:ratchet-bank (scripts/quality/verify-ratchet-bank.mjs) |
| Доставляет | один всегда актуальный PR в релизную ветку — принудительно обновляемый и не создающий спама |
Фиксация выполняется пакетно, а не при каждом push, поскольку у неё нет требований к задержке (зафиксировать снижение в течение 8 часов вполне допустимо), тогда как запуск при каждом слиянии многократно пересобирал бы ветку PR во время серий слияний и каждый раз требовал бы полного прохода ESLint. Обнаружение по-прежнему выполняется при push (release-green); пакетно выполняется только фиксация.
Верификатор безопасности
Заголовок раздела «Верификатор безопасности»Задание изменяет базовые уровни без вмешательства человека, поэтому приемлемость этого обеспечивает verify-ratchet-bank.mjs. Он сравнивает дерево после --update с HEAD и прерывает задание до создания какого-либо коммита, не открывая PR, если каждое изменение не относится к одному из следующих типов:
- числовая запись
frozen/testFrozenснижена или удалена complexity-baseline.json→countсниженоquality-baseline.json→metrics.cognitiveComplexity.valueснижено
Любые другие изменения приводят к сбою: повышение числа, добавление записи, изменение cap/testCap либо удаление/перезапись заметки _rebaseline_* (эти заметки служат журналом аудита, объясняющим причину существования каждого потолка, и хранятся внутри того же объекта frozen, что и записи файлов). Бот, способный повысить предел, был бы однозначно хуже текущего положения дел. Защита от регрессий: tests/unit/verify-ratchet-bank.test.ts.
Задание никогда не выполняет push в release/* — PR сливает человек, поэтому ошибочное измерение не может попасть в ветку без проверки.
Политика списка разрешений
Заголовок раздела «Политика списка разрешений»Каждая проверка, которая не должна завершаться ошибкой из-за ранее существовавших нарушений, использует зафиксированный список разрешений
(например, KNOWN_STALE_DOC_REFS, KNOWN_MISSING, KNOWN_RAW_SQL). Политика такова:
Устраняйте первопричину; используйте список разрешений только тогда, когда нарушение существовало ранее и не может быть исправлено в том же PR.
При добавлении записи в список разрешений:
- Добавьте комментарий с обоснованием.
- Укажите ссылку на задачу для отслеживания (например,
// #3498 — Функциональность этапа 2, ещё не реализована). - Удалите запись в том же PR, который исправляет нарушение, — устаревшая запись, которая больше не подавляет активное нарушение, сама является дефектом (проверка устаревших правил 6A.3 после реализации будет завершаться ошибкой при наличии бесхозной записи в списке разрешений).
Не добавляйте записи в список разрешений, чтобы тесты проходили быстрее. Успешная проверка при растущем списке разрешений создаёт ложное ощущение качества.
Если проверка завершается ошибкой в вашем PR
Заголовок раздела «Если проверка завершается ошибкой в вашем PR»- Внимательно прочитайте вывод проверки — в нём точно указано, какой файл или символ нарушил правило.
- Исправьте нарушение — большинство проверок представляют собой детерминированные проверки файловой системы, которые проходят, как только код исправлен.
- Если нарушение существовало ранее (то есть вы его не вносили, но теперь оно охватывается проверкой): добавьте запись в список разрешений с комментарием-обоснованием и ссылкой на задачу для отслеживания.
- Если проверка использует храповый механизм (покрытие, предупреждения ESLint, дублирование, сложность):
ваше изменение ухудшило метрику. Исправьте первопричину или (в редких случаях) выполните
npm run quality:ratchet -- --update, если изменение было намеренным и ухудшение метрики допустимо, — но объясните причину в описании PR. - Рекомендательные проверки (
continue-on-error: true) носят информационный характер — они не блокируют слияние, но отображаются в сводке CI. Тем не менее исправляйте их.
Добавление новой проверки
Заголовок раздела «Добавление новой проверки»- Создайте
scripts/check/check-<name>.mjs(или.ts). Проверки политик завершаются с кодом 0/1. Проверки с храповым механизмом записывают метрику вquality-metrics.jsonчерезcollect-metrics.mjs. - Добавьте
"check:<name>": "node scripts/check/check-<name>.mjs"вpackage.json. - Подключите её в
.github/workflows/ci.ymlв рамках соответствующего задания (политика →lintилиdocs-sync-strict; храповый механизм →quality-gate). - Если у неё есть список разрешений, примените
reportStaleEntries()изscripts/check/lib/allowlist.mjs, чтобы устаревшие записи обнаруживались автоматически. - Напишите тест в
tests/unit/build/, покрывающий логику обнаружения нарушений этой проверкой. - Обновите этот документ (добавьте строку в таблицу соответствующего задания).
Инструменты для агентов: LSP в цикле разработки (по желанию)
Заголовок раздела «Инструменты для агентов: LSP в цикле разработки (по желанию)»Помимо проверок CI, OmniRoute поставляется с опциональной заготовкой agent-lsp
(проектный файл .mcp.json, этап 7, задача 15). Создайте .mcp.json,
чтобы предоставить агентам разработки доступ к языковому серверу TypeScript и позволить им разрешать символы /
диагностику до написания кода — это дополняющий typecheck:core подход «компиляция до утверждения»,
который устраняет ошибки с «выдуманными символами» в самом источнике. Заготовка намеренно
не загружается автоматически (вы сами выбираете и проверяете мост MCP↔LSP); некорректная запись лишь регистрирует
ошибку подключения и никогда не нарушает работу сеансов.
Бэклог рационализации (оценка ROI — фаза 9, волна 3)
Заголовок раздела «Бэклог рационализации (оценка ROI — фаза 9, волна 3)»Этот перечень был сверен с ci.yml 2026-06-17 (в предыдущей версии были пропущены
audit:deps, check:tracked-artifacts, check:lockfile, check:licenses,
check:dead-code, check:cognitive-complexity, check:type-coverage,
check:codeql-ratchet, check:pr-evidence). Оценка ROI сверенного набора
выявила следующие кандидатуры на рационализацию. Объединения представляют собой механические
изменения CI; включение обязательного режима и удаление — это решения в области политик, остающиеся за оператором. Ничто из перечисленного ниже
пока не применено.
Также не задокументированы выше (рекомендательные проверки с низкой информативностью): задание docs-lint
(markdownlint + Vale, для всего задания задано continue-on-error) и автономные рабочие процессы сканирования
semgrep.yml / codeql.yml / scorecard.yml. Значение semgrepFindings: 0 присутствует в
quality-baseline.json, но не подключено к блокирующему храповому механизму в ci.yml — в настоящее
время эта метрика изолирована.
Объединение / устранение дублирования (механические изменения, более низкий риск)
Заголовок раздела «Объединение / устранение дублирования (механические изменения, более низкий риск)»Каждая кандидатура была проверена на соответствие фактическому состоянию шлюзов 2026-06-17 (доверяй, но проверяй); несколько «очевидных» объединений, как выяснилось, скрывают технический долг и не являются чистыми прямыми заменами.
check:docs-syncзапускается дважды — отдельно в заданииlint, а затем ещё раз внутриcheck:docs-all(docs-sync-strict) и в pre-commit-хуке husky. ✅ ВЫПОЛНЕНО — отдельный вызов изlintудалён.- Сканирование CVE — ❌ НЕ является чистым объединением.
audit:depsзавершается с ошибкой при любой CVE высокой/критической серьёзности;check:vuln-ratchet(osv) завершается с ошибкой только при регрессии относительно базового уровня (сейчас 1 MODERATE). Семантика различается — удалениеaudit:depsпривело бы к потере абсолютного шлюза для высокой/критической серьёзности. Сохранить оба. - Обнаружение циклов — ❌ НЕ является чистым объединением.
check:circular-deps(dpdm) сообщает о 91 цикле (поэтому эта проверка и является рекомендательной); её нельзя сделать блокирующей, не устранив сначала эти циклы, а область её действия шире, чем у успешно проходящей курируемой проверкиcheck:cycles. Оставитьcheck:cyclesблокирующей; устранение 91 цикла dpdm — отдельная задача в бэклоге. - Сложность — ✅ ВЫПОЛНЕНО (
check:complexity-ratchets/eslint.complexity-ratchets.config.mjs): один проход ESLint, подсчёт по ruleId, поэтому базовые уровни цикломатической сложности+max-lines и когнитивной сложности остаются независимыми; отдельныеcheck:complexity/check:cognitive-complexityсохранены для локального запуска с--update. - Защита от галлюцинаций
/api— ✅ ВЫПОЛНЕНО (check:api-docs-refs+scripts/check/lib/apiRoutes.mjs): одна инвентаризацияsrc/app/apiчерез ФС, openapi-routes + docs-symbols по-прежнему формируют отчёты независимо; отдельные проверки сохранены для локальных запусков. check:node-runtimeзапускается в 11 заданиях — ⚠️ низкий ROI. Каждое из них выполняется на отдельном раннере, а проверка занимает <1 с; общая экономия составит ~10 с ценой потери дешёвой проверки в каждом задании. Изменения того не стоят.typecheck:noimplicit:coreв CI lint — ✅ удалено из задания lint (проверка была рекомендательной сcontinue-on-error); блокирующая проверка поверхности типов обеспечиваетсяtypecheck:core+check:type-coverage. Локальный скрипт сохранён.
Включить обязательный режим / принять решение (политика оператора)
Заголовок раздела «Включить обязательный режим / принять решение (политика оператора)»check:openapi-security-tiers(рекомендательная) — ❌ нельзя просто сделать блокирующей. Она завершается с кодом 0, но предупреждает, что у нескольких маршрутовtraffic-inspectorвLOCAL_ONLY_API_PREFIXESотсутствует аннотацияx-loopback-only: true. Для её обязательного применения необходимо сначала добавить эти аннотации вopenapi.yaml.typecheck:noimplicit:core(рекомендательная) — в значительной степени перекрывается блокирующим храповым механизмомcheck:type-coverage. Преобразовать в храповую проверку или удалить избыточный второй проходtsc.test:vitest:ui(теперь блокирующая) — существовавшие ранее сбои явно исключены вvitest.config.tsс отслеживающими комментариями// #8618; новые сбои приводят к ошибке задания.check:secrets(gitleaks, блокирующий храповой механизм, зафиксированный на уровне 3 задокументированных ложноположительных результатов) — добавить эти 3 результата в список разрешённых, чтобы достичь 0, либо перевести проверку в рекомендательный режим. Перекрывается встроенным сканированием секретов GitHub +check:public-creds.check:pr-evidence(блокирующая, выполняет grep по тексту тела PR) — высокий риск ложноположительных результатов; её удаление ослабит контроль соблюдения жёсткого правила №18, поэтому это действительно вопрос политики.semgrep(автономная рекомендательная проверка) — пересекается с CodeQL по семействам OWASP; подключить её базовый уровень к храповому механизму или удалить.
Связанная документация
Заголовок раздела «Связанная документация»- Цепочка поставок (происхождение, SBOM, Trivy, Scorecard):
docs/security/SUPPLY_CHAIN.md
check-key-completeness — проверка соответствия наборов ключей
Заголовок раздела «check-key-completeness — проверка соответствия наборов ключей»scripts/i18n/check-key-completeness.mjs (npm run i18n:check-keys, задание i18n-ui-coverage).
Сравнивает набор конечных ключей каждого файла src/i18n/messages/<locale>.json с en.json и завершает
работу с ошибкой при наличии любого отсутствующего или лишнего конечного ключа, независимо от того, когда ключ был добавлен. Заполнители __MISSING__:
считаются присутствующими (их содержимое относится к компетенции проверки доли). Это абсолютное дополнение
двух проверок на основе различий/процентов: check-ui-keys-coverage устанавливает минимальный порог 80 % для каждой
локали (43 отсутствующих ключа из ~13 000 всё ещё дают 99,7 %), а check-new-key-coverage оценивает
только ключи, которые PR добавляет в en.json. Пакет локалей создаётся на основе версии en.json на день
ответвления его ветки, после чего перевод выполняется несколько дней, пока базовая ветка продолжает получать новые ключи; сам PR пакета не добавляет
ключей, поэтому обе соседние проверки промолчали, когда пакет 1 (#13044) был влит с нехваткой 43 ключей в девяти
локалях, а пакет 2 (#13660) — с нехваткой 10 ключей в восьми (2026-09-15). Чтобы исправить ошибку, выполните
node scripts/i18n/sync-ui-keys.mjs --locale=<codes> --translate-markers; конечный ключ extra
означает, что он был удалён из источника — удалите его из локали. --warn выводит отчёт без завершения с ошибкой.
--catalog=cli выполняет такое же сравнение для bin/cli/locales (npm run i18n:check-keys:cli);
оба шага находятся в задании i18n-ui-coverage.
check-new-key-coverage — проверка интернационализации новых ключей
Заголовок раздела «check-new-key-coverage — проверка интернационализации новых ключей»Соседняя проверка для check-ui-value-drift. Та обнаруживает случай, когда английское значение было переписано,
а его переводы не были обновлены; эта же обнаруживает случай, когда английский ключ был добавлен,
но некоторые локали его так и не получили.
check-ui-keys-coverage не может обнаружить такой случай: она устанавливает процентный порог для каждой локали, а
одиннадцать отсутствующих ключей из ~13 000 оставляют покрытие на уровне 99,9 %. Процентный показатель для языка не может
выразить ситуацию «эта функция выпущена без перевода» — целая функция может появиться в новой локали без какого-либо
текста и вообще не изменить этот показатель.
Инцидент, который она предотвращает: на этапе 3 Orchestration Canvas одиннадцать ключей были переведены на
42 локали, существовавшие на тот момент. Несколько часов спустя пакет языков ЕС (#13044) увеличил число локалей в репозитории
до 51, а девять новых локалей (el, et, ga, hr, lt, lv, mt, sl, sr) так и не
получили эти ключи. deepMergeFallback подставляет английский текст вместо отсутствующего ключа, поэтому результатом был
непереведённый, а не пустой интерфейс — реальная проблема, по своей природе остававшаяся незаметной.
Как и соседняя проверка, она учитывает различия, сравнивая английский текст в точке слияния базовых веток с рабочим деревом, поэтому существовавшие ранее пробелы остаются зафиксированными, и для включения проверки миграция не потребовалась.
Маркер __MISSING__:<english> не удовлетворяет этой проверке (с 2026-09-17). Ранее это был
документированный способ отложить перевод — во время выполнения вместо него подставляется корректный английский текст, — пока восемь PR с функциями от
2026-09-16 не добавили 61 ключ и не проставили этот маркер во всех 65 локалях вместо перевода: данная
проверка приняла каждый из них, ничто не заблокировало PR, а затем блокирующая проверка доли реальных переводов
завершилась с ошибкой на вершине релизной ветки для всех (pt-BR 3,2 % > 2,5 % + 0,5). Теперь маркер считается
отсутствующим переводом. Чтобы исправить ошибку, выполните
node scripts/i18n/sync-ui-keys.mjs --locale=<codes> --translate-markers --batch-size=40 либо
обработайте все локали параллельно с помощью npm run i18n:translate-new-keys (scripts/i18n/translate-new-keys.sh,
безопасно для отсоединённого режима, отказывается запускаться без переменных окружения OMNIROUTE_TRANSLATION_*). Ключ, который должен оставаться
на английском языке (закреплённое название продукта, движка или флага), следует помещать в scripts/i18n/untranslatable-keys.json,
а не скрывать за маркером. vi полностью запрещает маркеры (tests/unit/i18n-vi-completeness.test.ts).
check-vitest-exclusions — проверка отложенных тестов
Заголовок раздела «check-vitest-exclusions — проверка отложенных тестов»Файл в списке exclude конфигурации vitest.config.ts — это тест, который не запускается, хотя для тех, кто просматривает
дерево, он выглядит как часть покрытия. За комментарием
// #8618 — pre-existing failure; remove this exclusion when fixed накопилось шестьдесят два файла. Задача #8618 была закрыта
2026-08-11, в то время как отслеживаемый ею список вырос с 45 до 62 записей, каждая новая запись наследовала комментарий,
ссылавшийся на уже закрытую задачу. Когда список наконец проверили файл за файлом (#13204), 51 из 62 файлов
успешно прошёл тестирование на текущем дереве без каких-либо изменений исходного кода.
Проверка требует, чтобы каждое исключение, соответствующее реальному файлу, (a) указывало отслеживающую задачу и
(b) присутствовало в config/quality/vitest-exclusions.json с измеренным статусом, чтобы добавление исключения
представляло собой проверяемое изменение в отдельном файле, а не ещё одну строку в массиве из 60 записей. Она намеренно
не запускает исключённые тесты повторно — это занимает около 10 минут и должно выполняться периодическим заданием;
в реестре фиксируется дата последней проверки каждого из них.
HagiCode
HagiCode — агентная среда разработки со структурированными процессами, параллельным выполнением несколькими агентами и интерфейсами Hero Dungeon.
Превращайте идеи в полезное ПО с более умным, быстрым и увлекательным агентным рабочим процессом.

- SmartСтруктурированные процессы превращают намерение в исполнимый путь от идеи до готового изменения.
- EfficientМультиагентные процессы параллельно продвигают исследование, реализацию и проверку.
- FunHero Dungeon делает длительную совместную разработку наглядной и увлекательной.