Перейти к содержимому
OmniRoute source

Quality-Gate System — Critical Assessment, Catalog and Replication Playbook (Русский)

Часть 1 — Вердикт и классификация зрелости

Заголовок раздела «Часть 1 — Вердикт и классификация зрелости»

Общая оценка: A− / «Продвинутый уровень». Входит примерно в 5–10% лучших проектов. Система независимо реализует несколько паттернов, которые явно выделяются в отрасли, — и это наиболее весомый признак соответствия (мы не копировали контрольный список, а самостоятельно пришли к правильным практикам).

Эталонный фреймворк Наше положение Оценка
OWASP DSOMM (5 уровней, 5 измерений) Уверенный уровень 3 с приближением к 4 по направлениям интенсивности тестирования и глубины статического анализа. Большинство организаций находятся на уровнях 1–2. L3→L4
OpenSSF Scorecard (18 проверок) Мы проходим CI-Tests, Code-Review, Dependency-Update-Tool, Fuzzing, SAST, Signed-Releases (provenance), Token-Permissions, Vulnerabilities, Dangerous-Workflow. Пробелы: Branch-Protection для main отключена; некоторые actions не закреплены по версиям. ~7–8/10
SLSA (4 уровня) npm publish --provenance + id-token: write + сборка на инфраструктуре GitHub = L2 с приближением к L3. Для L3+ отсутствует защищённая/герметичная среда сборки. L2→L3
SonarQube «Clean as You Code» Идентичная философия: трещотка предотвращает регрессию (новый код не ухудшает метрику). Отличие: Sonar рекомендует небольшое количество условий; у нас около 46 барьеров (риск усталости от проверок). Соответствует, с оговоркой
Паттерн Quality-Ratchet Эталонная реализация: трещотка + dedicatedGate + tightenSlack + --require-tighten + корректный пропуск при невозможности выполнения. Более продвинутая, чем большинство общедоступных примеров. Образцово
DORA 2024 Очень сильные позиции по оси стабильности. Риск: большое количество барьеров может увеличить время выполнения изменений — это смягчается разделением быстрых барьеров, однако остаётся пробел в покрытии (см. Часть 2). Сильная (стабильность)
OWASP LLM Top 10 (2025) Мы покрываем риск №1 (инъекция промпта) с помощью защиты во время выполнения + promptfoo (оценка) + garak (red-team-тестирование). Стандартные отраслевые инструменты. Покрыт
Мутационное тестирование Stryker запускается каждую ночь, пороговые значения — 70/50, охвачено 8 критически важных модулей. Отраслевой консенсус (60% для существующего / 80% для нового кода, ночные запуски) — мы превосходим его. Пробел: показатель пока не контролируется трещоткой. Почти готово

Часть 2 — Критическая оценка (сильные стороны + честные недостатки)

Заголовок раздела «Часть 2 — Критическая оценка (сильные стороны + честные недостатки)»
  1. Храповый механизм на основе нескольких метрик. Сердце системы. 24 метрики в quality-baseline.json
    • 4 выделенные базовые линии, каждая с направлением (up/down), допуском (eps), запасом (tightenSlack) и флагом dedicatedGate. То, что исправлено, остаётся исправленным — это противоядие от энтропии кодовой базы.
  2. Многоуровневая защита цепочки поставок. SAST (CodeQL/Sonar) + секреты (gitleaks с useDefault) + SCA (osv/npm-audit/Trivy/Dependabot) + лицензии + lockfile + SBOM + аттестация происхождения SLSA + Scorecard + усиление безопасности рабочих процессов (zizmor). Мало в каких кодовых базах есть настолько полный набор.
  3. Противоядия от закона Гудхарта. Покрытие как цель — классический антипаттерн («когда показатель становится целью, он перестаёт быть хорошим показателем»). У нас есть противовесы: мутационное тестирование (измеряет, обнаруживает ли тест ошибку, а не просто выполняет ли он строку), check-test-masking (не позволяет ослаблять проверки ради успешного прохождения), минимальные пороги покрытия для каждого модуля (заставляют тестировать код с ВЫСОКИМ риском, а не только простые части) и check-pr-evidence (жёсткое правило № 18).
  4. Проверки против галлюцинаций и несогласованности. Редкая и ценная категория: check-known-symbols, check-fetch-targets, check-openapi-routes, check-docs-symbols гарантируют, что документация, спецификации и строковая диспетчеризация ссылаются на существующие символы. Выявляют «гниение», которое не обнаруживают линтеры и тесты.
  5. Жизненный цикл от рекомендательных до блокирующих проверок. Новые проверки сначала добавляются как рекомендательные (не блокируют слияния в период доработки), а в конце цикла становятся блокирующими. Это снижает трение, не опуская планку.
  6. Корректный пропуск при отсутствии инфраструктуры. Сканеры (--ratchet) завершаются с exit 0, если не работает бинарный файл или сеть, — отсутствие инфраструктуры никогда не блокирует легитимный PR. Признак зрелой инженерной практики.
  7. Формализованная культура. Жёсткие правила + trust-but-verify + контроль устаревших списков разрешений + проверка доказательств превращают дисциплину в автоматизированную верификацию.
  1. 🔴 Разделение быстрых проверок всё ещё оставляет структурный пробел. quality.yml (PR→release/**) теперь запускает проверку типов, быстрые детерминированные тесты и рекомендательную production-сборку для PR с изменениями кода, но по-прежнему не запускает полный набор проверок release-PR из ci.yml (храповые механизмы покрытия, артефакт пакета, интеграционные тесты, E2E, SonarQube). Мотивация (скорость) обоснованна, но проверка должна выполняться там, где происходит слияние (shift-left). Крупнейшее ожидающее структурное исправление.
  2. 🟠 Риск разрастания проверок и усталости от них. ~46 проверок + 25 заданий — это ОЧЕНЬ МНОГО. Сам Sonar предупреждает: слишком большое количество условий приводит к «усталости от проверок» и спорам о приоритетах, из-за чего проверку могут проигнорировать. DORA предупреждает, что тяжёлые проверки увеличивают lead time. Мы снижаем этот риск с помощью рекомендательных уровней и неабсолютных храповых механизмов, но отсутствует периодическая оценка ROI каждой проверки (некоторые микропроверки синхронизации документации можно объединить).
  3. 🟠 Показатель мутационного тестирования ещё не использует храповый механизм. Самое сильное противоядие от манипуляций с покрытием пока остаётся рекомендательным. Это самый ценный из ожидающих пунктов (и он уже готов на 90%).
  4. 🟡 Рекомендательные проверки, которые должны быть блокирующими (при правильном охвате). osv (vulnCount) и oasdiff остаются рекомендательными, несмотря на зафиксированные базовые линии. Рекомендательный режим osv имеет смысл (новая CVE в старой зависимости блокировала бы несвязанный PR), но существует золотая середина: блокировать только CRITICAL+fixable, как мы сделали с Trivy. Рекомендательный статус oasdiff означает, что изменение, нарушающее контракт, может пройти.
  5. 🟡 Проверки безопасности во время выполнения запускаются только по ночам. schemathesis/garak/promptfoo/chaos/k6 запускаются ночью. Это правильное решение (они медленные и требуют работающего сервера), но PR может внести регрессию защиты от инъекций, которая будет обнаружена лишь следующей ночью.
  6. 🟡 Защита ветки main ОТКЛЮЧЕНА. BRANCH_LOCK_TOKEN блокирует ветки release, но сама ветка main не защищена. Scorecard/DSOMM снижают за это оценку. Требуется действие владельца.
  7. 🟡 CodeQL использует конфигурацию по умолчанию; semgrep не формализован. Конфигурация по умолчанию работает (0 предупреждений), но зафиксированный в репозитории codeql.yml даёт больше контроля; semgrep запускается через внешнюю облачную платформу, а его конфигурация не версионируется в репозитории.

Часть 3 — Полный каталог контрольных точек качества (переносимый)

Заголовок раздела «Часть 3 — Полный каталог контрольных точек качества (переносимый)»

Приведённые ниже 12 категорий представляют собой «систему качества» в пригодной для повторного использования форме. Для каждой указаны цель (что необходимо защитить), используемые нами инструменты и независимый от инструментов эквивалент, позволяющий воспроизвести её на любом стеке.

1. Стиль и форматирование (детерминированно, быстро)

Заголовок раздела «1. Стиль и форматирование (детерминированно, быстро)»
  • OmniRoute: Prettier + ESLint через lint-staged (pre-commit), 2 пробела/двойные кавычки/100 символов в строке.
  • Общий подход: один форматтер с автоматическим исправлением + один линтер, запускаемые в pre-commit для файлов в staging area.
  • OmniRoute: typecheck:core (блокирующая проверка) + typecheck:noimplicit:core (рекомендательная проверка) + храповик type-coverage на уровне 92.17% + бюджет any для каждого файла.
  • Общий подход: строгая проверка типов в CI + метрика покрытия типами с храповиком + бюджет any/обходных механизмов для каждого файла.
  • OmniRoute: 2 непересекающихся средства запуска тестов (встроенное в Node + vitest), 8 шардов, глобальное покрытие 60/60/60/60 + храповик ~76% + 8 минимальных порогов для критически важных модулей + ночные тесты свойств + ночное мутационное тестирование.
  • Общий подход: средство или средства запуска тестов + абсолютный минимальный порог покрытия (защита от нулевого покрытия) + храповик покрытия (защита от регрессии) + минимальные пороги для модулей с высоким риском (защита от закона Гудхарта) + тестирование на основе свойств для чистой логики + ночное мутационное тестирование как реальная мера качества тестов.

4. Политика тестирования (защита от манипуляций)

Заголовок раздела «4. Политика тестирования (защита от манипуляций)»
  • OmniRoute: pr-test-policy (продуктовый код требует теста), check-test-masking (блокирует ослабление проверок), pr-evidence (заявление об успехе требует блока с доказательствами), test-discovery (каждый тест обнаруживается средством запуска).
  • Общий подход: проверка «новый код ⇒ новый тест» + детектор удалённых проверок/тавтологий + требование доказательств (TDD или живой тест) + гарантия отсутствия потерянных тестов за пределами glob-шаблонов.
  • OmniRoute: предупреждения ESLint (3769↓), дублирование jscpd (5.72%↓), цикломатическая сложность + максимальное количество строк (1800↓), когнитивная сложность sonarjs (753↓), мёртвый код/неиспользуемые экспорты knip (339↓), размер каждого файла (зафиксирован, допускается только уменьшение), циклические зависимости (собственная реализация алгоритма Тарьяна, блокирующая проверка).
  • Общий подход: применять храповик к каждой метрике здоровья кода (предупреждения, дублирование, цикломатическая и когнитивная сложность, мёртвый код, размер файлов, циклы импортов). Направление всегда одно: «не допускать регрессии».
  • OmniRoute: CodeQL (храповик предупреждений = 0), gitleaks ([extend] useDefault=true — критически важно!), SonarQube, собственные правила безопасности (public-creds, error-helper, route-guard-membership, route-validation).
  • Общий подход: SAST (CodeQL/Sonar/semgrep) с храповиком предупреждений + сканер секретов с унаследованным набором правил по умолчанию (пользовательская конфигурация, переопределяющая правила по умолчанию, создаёт слепую зону) + проектные шлюзы безопасности на основе жёстких правил.
  • OmniRoute: osv-scanner + npm-audit + Trivy + Dependabot (SCA), license-checker (список разрешённых лицензий SPDX), lockfile-lint (HTTPS+sha512+registry), check-deps для защиты от slopsquatting (список разрешённых пакетов + возраст ≥72 ч).
  • Общий подход: SCA по нескольким источникам + список разрешённых лицензий + проверка целостности lock-файла + список разрешённых зависимостей с проверкой возраста/тайпсквоттинга + бот для сгруппированного обновления зависимостей.
  • OmniRoute: SBOM (CycloneDX + syft), подтверждение происхождения SLSA (--provenance), OpenSSF Scorecard (еженедельно), усиление защиты рабочих процессов (zizmor: artipacked→persist-credentials:false, отравление кеша, разрешения токенов).
  • Общий подход: создавать SBOM при публикации + подписанное подтверждение происхождения (SLSA L2+) + запускать Scorecard по расписанию + усиливать защиту всех рабочих процессов (токены с минимальными привилегиями, отсутствие сохранённых учётных данных при checkout без последующей отправки изменений, фиксация actions по SHA).
  • OmniRoute: oasdiff (критические изменения OpenAPI), schemathesis (ночной фаззинг контрактов), openapi-coverage (процент документированных маршрутов, храповик 38.3%), openapi-security-tiers (спецификация в сравнении с защитой маршрутов).
  • Общий подход: сравнение контрактов для выявления критических изменений (oasdiff/buf) + фаззинг на основе свойств относительно спецификации (schemathesis) + покрытие документацией с храповиком + согласованность спецификации и кода.

10. Документация и i18n (защита от устаревания)

Заголовок раздела «10. Документация и i18n (защита от устаревания)»
  • OmniRoute: docs-sync (зеркально отражённые версии), docs-counts-sync (числа в документации в сравнении с кодом), env-doc-sync, doc-links, fabricated-docs, cli-i18n, i18n-ui-coverage (--threshold=65 + храповик 80.1%).
  • Общий подход: синхронизация версий/чисел/переменных окружения между документацией и кодом (автоматический шлюз вместо доверия) + проверка внутренних ссылок + покрытие i18n с храповиком.

11. Защита от галлюцинаций / согласованность (редкая категория)

Заголовок раздела «11. Защита от галлюцинаций / согласованность (редкая категория)»
  • OmniRoute: known-symbols (строковая диспетчеризация ⇒ существующий символ), provider-consistency, fetch-targets (клиентский fetch ⇒ реальный маршрут), docs-symbols, db-rules (жёсткие правила №2/№5), migration-numbering.
  • Общий подход: для каждого «дублированного источника истины» (реестр, строковая диспетчеризация, межслойные ссылки) необходим шлюз, доказывающий согласованность обеих сторон. Это выявляет деградацию, которую не обнаруживают проверка типов и тесты.

12. Отказоустойчивость и предметная область (специфика продукта)

Заголовок раздела «12. Отказоустойчивость и предметная область (специфика продукта)»
  • OmniRoute: chaos (внедрение отказов), heap-growth (утечки), k6 (длительная нагрузка), promptfoo+garak (тестирование LLM методом red team по OWASP LLM Top 10), 3 закона отказоустойчивости (circuit-breaker/cooldown/lockout).
  • Общий подход: определите режимы отказа, характерные для вашей предметной области, и создайте для каждого автоматический шлюз, даже если он запускается только ночью. Для приложений с ИИ: red team-тестирование на инъекции. Для распределённых систем: хаос-тестирование + проверка утечек + длительное нагрузочное тестирование.

Часть 4 — План внедрения для любого проекта

Заголовок раздела «Часть 4 — План внедрения для любого проекта»

Внедряйте систему поэтапно, причём каждый этап должен приносить самостоятельную пользу. Не пытайтесь охватить все 12 категорий сразу — это приводит именно к той усталости от проверок, о которой предупреждает Часть 2. Каждая новая проверка сначала работает в рекомендательном режиме и становится блокирующей, когда стабилизируется.

Центральный переиспользуемый элемент: «анатомия храповой проверки»

Заголовок раздела «Центральный переиспользуемый элемент: «анатомия храповой проверки»»

Вся система строится вокруг следующего шаблона из 3 файлов. Сначала скопируйте его:

  1. baseline.json — зафиксированное значение метрики + direction (up/down) + eps (защита от нестабильности) + tightenSlack + dedicatedGate.
  2. collect-metrics.<ext> — запускает инструмент, извлекает числовое значение и записывает его в metrics.json.
  3. check-ratchet.<ext> — сравнивает metrics.json с baseline.json; завершает работу с exit 1 только при регрессии сверх eps; завершает работу с exit 0 (корректный пропуск), если инструмент или инфраструктура недоступны; при указании --require-tighten завершает работу с exit 1, если показатель улучшился, но базовый уровень не был обновлён (фиксирует достигнутое улучшение).

После внедрения этого шаблона каждая новая метрика (покрытие, сложность, предупреждения, оповещения SAST, размер бандла, показатель мутационного тестирования…) — это всего лишь одна строка в базовом уровне.

CI настроен; форматтер + линтер + проверка типов + один исполнитель тестов + абсолютный минимальный порог покрытия (например, 60%). Pre-commit запускает быстрые проверки, ошибки которых можно исправить автоматически. Результат: ни один PR не нарушает базовые требования.

Этап 1 — Механизм храповика (неделя 2) — основа всего

Заголовок раздела «Этап 1 — Механизм храповика (неделя 2) — основа всего»

Реализуйте описанные выше 3 файла. Зафиксируйте базовые уровни для предупреждений, покрытия, сложности, дублирования, мёртвого кода и размера файлов. Результат: с этого момента кодовая база может только улучшаться.

Этап 2 — Углублённый статический анализ (неделя 3)

Заголовок раздела «Этап 2 — Углублённый статический анализ (неделя 3)»

SAST (CodeQL/Sonar/semgrep) с храповиком для оповещений; сканер секретов (наследуйте набор правил по умолчанию); SCA (osv/Dependabot) + список разрешённых лицензий + lockfile-lint. Результат: известные уязвимости и утёкшие секреты не проходят проверки.

Этап 3 — Цепочка поставки сборки (неделя 4)

Заголовок раздела «Этап 3 — Цепочка поставки сборки (неделя 4)»

SBOM при публикации + подписанное подтверждение происхождения (SLSA L2) + Scorecard по расписанию + усиление защиты рабочих процессов (zizmor: минимальные токены, отсутствие сохранённых учётных данных, зафиксированные версии actions). Результат: прослеживаемые и защищённые от подмены релизы.

Этап 4 — Интенсивность тестирования (недели 5–6)

Заголовок раздела «Этап 4 — Интенсивность тестирования (недели 5–6)»

Второй исполнитель тестов, если это полезно; минимальные пороги покрытия по модулям для критически важных модулей (защита от закона Гудхарта); тестирование на основе свойств для чистой логики; еженощное мутационное тестирование → после получения первого результата сделайте mutationScore храповой метрикой. Результат: покрытие перестаёт быть показателем тщеславия; тесты доказуемо выявляют ошибки.

Этап 5 — Контракты и динамический анализ (неделя 7)

Заголовок раздела «Этап 5 — Контракты и динамический анализ (неделя 7)»

Если есть публичный API: oasdiff (критические изменения, блокирующая проверка) + schemathesis (еженочный фаззинг). Еженочные DAST-тесты и тесты методом красной команды — в зависимости от предметной области. Результат: контракты не нарушаются незаметно.

Этап 6 — Защита от галлюцинаций и предметно-ориентированные проверки (неделя 8)

Заголовок раздела «Этап 6 — Защита от галлюцинаций и предметно-ориентированные проверки (неделя 8)»

Одна проверка согласованности для каждого случая «дублированной истины» в проекте. Проверки режимов отказа, специфичных для предметной области (для ИИ: тестирование методом красной команды на инъекции). Результат: структурная деградация и предметно-специфичные сбои перекрыты защитной сеткой.

  • Цикл «рекомендательная→блокирующая» для каждой новой проверки.
  • stale-allowlist: у каждого подавления есть обоснование + issue; устаревшие подавления выявляются.
  • evidence-gate: заявление об успехе в PR требует доказательства (теста или постоянно действующего теста).
  • Ежеквартальная оценка окупаемости каждой проверки (отключайте или лишайте ресурсов те, которые не окупаются, — это снижает усталость).
  • Превращайте строгие правила вашего проекта в исполняемые проверки.

Сквозные принципы (не подлежат обсуждению)

Заголовок раздела «Сквозные принципы (не подлежат обсуждению)»
  • Храповик, а не абсолютное значение. Проверяйте отсутствие регрессии, а не фиксированное число (за исключением ненулевых минимальных порогов).
  • Абсолютный порог и храповик вместе. Порог предотвращает обвал; храповик предотвращает постепенную деградацию.
  • Защита от закона Гудхарта по замыслу. Для каждой целевой метрики нужна уравновешивающая метрика (покрытие ⇒ мутационное тестирование + защита от маскировки; пороги по модулям, вынуждающие тестировать сложный код).
  • Корректный пропуск. Отсутствующая инфраструктура никогда не блокирует; блокирует только реальная регрессия.
  • dedicatedGate для ресурсоёмких метрик. Метрики, которым требуется внешний исполняемый файл, получают собственный скрипт (с возможностью пропуска) вне синхронного центрального храповика.
  • Размещайте проверку там, где происходит слияние. Не оставляйте разрыва между быстрой проверкой и фактическим слиянием (урок разделения быстрых проверок).
  • Немного блокирующих проверок, но хорошо подобранных. Sonar/DORA: слишком много условий = усталость. Предпочитайте рекомендательный режим + храповик стене из блокирующих проверок.

Часть 5 — Рекомендуемые улучшения (по приоритету, совместимые)

Заголовок раздела «Часть 5 — Рекомендуемые улучшения (по приоритету, совместимые)»

P0 — максимальная отдача, почти готово

  1. Храповик mutation score (после того как 1-й ночной запуск Stryker выдаст значения). Ключевое противоядие от закона Гудхарта применительно к покрытию; готово примерно на 90%.
  2. Закрыть оставшуюся дыру в быстрых гейтах — перевести production-сборку в quality.yml в обязательный режим после ознакомительной недели и продолжить переносить детерминированные проверки, выполняемые только для release PR, в путь PR→release.
  3. Защита ветки main (настройка владельца) — повышает Scorecard, закрывает пробел в DSOMM.

P1 — ценно 4. osv/oasdiff → блокирующие проверки с правильной областью действия — osv только для CRITICAL+fixable (в два этапа, как Trivy); oasdiff блокирует ломающие изменения. 5. require-tighten → блокирующая проверка (конец цикла) — закрепляет улучшения метрик. 6. Анализ отдачи/времени для каждого гейта в ci-summary — найти и удалить медленные/малоценные гейты.

P2 — убывающая отдача 7. SLSA L3 — герметичный/воспроизводимый сборщик (GitHub SLSA generator), если вы хотите перейти с L2 на более высокий уровень. 8. Закоммиченная конфигурация CodeQL + версионированный semgrep — больше контроля/воспроизводимости. 9. DAST smoke для каждого PR — быстрый поднабор schemathesis/promptfoo для наиболее рискованных эндпоинтов (не только ночью). 10. Дашборд нестабильности + метрики DORA — убедиться, что гейты не снижают скорость.


Часть 6 — Конкретные уроки релизов (гейты для добавления в Phase 9)

Заголовок раздела «Часть 6 — Конкретные уроки релизов (гейты для добавления в Phase 9)»

В этом разделе зафиксированы реальные инциденты при закрытии релизов, когда гейт отсутствовал, с конкретными доказательствами и предлагаемым гейтом. Каждый пункт является кандидатом для Части 5.

Урок v3.8.27 (2026-06-17) — «дыра в быстрых гейтах» позволяет детерминированным регрессиям дожить до дня релиза

Заголовок раздела «Урок v3.8.27 (2026-06-17) — «дыра в быстрых гейтах» позволяет детерминированным регрессиям дожить до дня релиза»

Что произошло. Во время /generate-release для v3.8.27 release PR (release/v3.8.27 → main) стал первым запуском полной матрицы ci.yml в интегрированном цикле. Результат: сразу 12 сбоев — 3 детерминированных теста + около 9 нестабильных сбоев/проблем окружения. Ни один из них не был регрессией работающего продукта, но все они остались незамеченными, поскольку PR цикла попадают в release/** через Fast QG (quality.yml), который НЕ запускает полный набор модульных тестов, pr-test-policy (маскировка тестов), полный набор интеграционных тестов или проверку паритета схем. Вот эти 3 детерминированных сбоя:

  1. Тест устарел из-за изменения UI — permissions modal switch buttons declare button type: #4034 добавил 4-й переключатель (a11y type="button" сохранился); проверка количества === 3 в тесте устарела. Статический анализ должен был обнаружить это в PR #4034.
  2. Тест устарел из-за изменения упаковки — findMissingArtifactPaths ... root runtime files: dist/http-method-guard.cjs стал допустимым обязательным путём; ожидаемый список в тесте устарел.
  3. Расхождение из-за модульности с потерей данных (самое серьёзное) — settings schemas accept ... unprefixed toggle: модульная версия updateSettingsSchema (schemas/settings.ts, созданная в #3988) разошлась с канонической (settingsSchemas.ts): 45 полей против 85 — 40 потеряно + 6 отличаются (qdrant*). Это был мёртвый код (во время выполнения используется каноническая версия), поэтому влияния на работающий продукт не было, но проблему обнаружил только написанный вручную тест паритета. #4030 восстановил 16 аналогичных пропусков из #3988/#3993, но этот случай остался незамеченным.

Предлагаемые гейты (Phase 9):

  • G1 — Фактически закрыть дыру в быстрых гейтах (расширяет P0 #2). В quality.yml (PR→release/**), помимо проверки типов + затронутых тестов, запускать pr-test-policy (маскировка тестов) + полный набор детерминированных модульных тестов (или хотя бы файлы статических проверок/проверок паритета, которые выполняются быстро и стабильно). Так устаревшие тесты и удаление утверждений будут обнаруживаться в том PR, который их вносит, — а не в день релиза. Не включать integration/e2e (медленные/нестабильные), но детерминированный слой НЕ МОЖЕТ оставаться только в PR→main.
  • G2 — Гейт паритета модульности (НОВЫЙ, сейчас не реализован). Проверка, которая для каждого символа, повторно экспортируемого модульным barrel-файлом (src/shared/validation/schemas/*, модули providerRegistry и т. д.), сравнивает структуру (ключи z.object, записи реестра) с каноническим источником и завершается с ошибкой при расхождении (пропущенное/лишнее поле). Она обнаружила бы потерю 40 полей из #3988 прямо в том PR. Обобщает написанные вручную тесты паритета (которые существуют только там, где кто-то не забыл их написать). Дёшево: импортирует обе версии и сравнивает Object.keys(shape).
  • G3 — Детерминированная сортировка нестабильных тестов (вспомогательное). Тесты запуска LiveWS и integration-combo/breaker завершаются сбоем из-за тайм-аута сервера/каскада в CI (окружение), а не из-за логики. Пометить их как known-flaky (поместить в карантин с заведённой задачей), чтобы красный статус release PR означал только реальные сигналы, а не шум, маскирующий детерминированные регрессии среди остальных результатов.

Принцип: гейт должен запускаться там, где происходит слияние (уже указано в «Сквозных принципах»). Инцидент v3.8.27 показывает, что это относится и к слою детерминированных тестов, а не только к lint/typecheck, — иначе долг из устаревших тестов + модульности с потерями проявляется только в PR→main, одной пачкой и в самый неподходящий момент.



Исходный код OmniRoute (a58000c7685f)

HagiCode

HagiCode — агентная среда разработки со структурированными процессами, параллельным выполнением несколькими агентами и интерфейсами Hero Dungeon.

Превращайте идеи в полезное ПО с более умным, быстрым и увлекательным агентным рабочим процессом.

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