Оркестратор контроля качества 1С-разработки. Определяет профиль изменения по трём осям (объём правки, архетипы кода, сложность), выбирает глубину каждого контура, запускает проверки, формирует отчёт с машиночитаемым следом и снимает блокирующий гейт. Вызывать после правок BSL или XML метаданных 1С, перед завершением работы и коммитом. Триггеры: «прогони гейт качества», «проверь код перед коммитом», «сними гейт», «отревьюй что я написал», «проверь по стандартам», «готов ли код к коммиту».
Scanned 8/30/2026
Install to Claude Code
npx -y skills add Romandredan/1c-quality-gate --skill quality-gate --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Quality Gate?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/romandredan-quality-gate)More formats (shields.io, HTML) on the badges page.
---
name: quality-gate
description: >-
Оркестратор контроля качества 1С-разработки. Определяет профиль изменения по трём осям
(объём правки, архетипы кода, сложность), выбирает глубину каждого контура, запускает
проверки, формирует отчёт с машиночитаемым следом и снимает блокирующий гейт.
Вызывать после правок BSL или XML метаданных 1С, перед завершением работы и коммитом.
Триггеры: «прогони гейт качества», «проверь код перед коммитом», «сними гейт»,
«отревьюй что я написал», «проверь по стандартам», «готов ли код к коммиту».
license: MIT
---
# quality-gate — оркестратор контроля качества 1С
Единственная точка входа плагина. Контуры проверки (`code`, `arch`, `xml`, `hygiene`) не
вызываются напрямую: сначала определяется **профиль изменения**, и уже он решает, какие
контуры и на какой глубине запускать.
> **Главное правило.** Полный прогон на правке комментария — налог, из-за которого гейт
> начинают обходить. Пропуск проверки без следа — ложная зелень. Поэтому глубина
> адаптивная, но **любой пропуск фиксируется явной записью с причиной**.
<ЖЁСТКИЙ-ШЛЮЗ>
По умолчанию — только проверка и отчёт. НЕ переписывай бизнес-логику и НЕ меняй метаданные
по своей инициативе. Правки применяются лишь в режиме `--fix` и только из безопасных
категорий. Находки уровня Critical и любые изменения логики, проведения, запросов, прав —
никогда без явного подтверждения пользователя.
</ЖЁСТКИЙ-ШЛЮЗ>
---
## Инварианты прогона
Восемь утверждений, без которых результат недействителен. Если из всего навыка усвоено
только это — прогон ещё имеет смысл; если нарушено любое из них — уже нет.
1. **Профиль считается один раз**, до контуров, и контуры его не пересчитывают.
2. **Глубина — по профилю, а не по привычке.** Не гонять архитектуру на опечатке и не
ограничиваться гигиеной на новом модуле проведения.
3. **Контур исполняется вызовом навыка**, а не воспроизведением по памяти.
4. **Строку следа инструментальной проверки печатает инструмент** — она не сочиняется и
не переписывается по смыслу.
5. **Любой пропуск — запись `skipped` с причиной.** Молчание неотличимо от выполнения, и
это единственная ошибка, которая обесценивает плагин целиком.
6. **Вердикт «чисто» обязан признавать непроверяемое** — записью `not_verified`.
7. **Каждая находка — с номером стандарта, кодом диагностики или названием эвристики** и
измеренным значением против порога; 🔴 и 🟠 блокируют вердикт «Чисто». Вне `--fix` —
только отчёт.
8. **Гейт снимается утилитой** `gate.mjs release`, а не удалением файла состояния.
---
## Шаг 1. Профиль изменения — три оси
Считается **один раз**, до запуска контуров.
**Пороги берутся из проекта, а не по памяти.** До расчёта осей выполни:
```bash
node "$QG/tools/config.mjs" show
```
Команда печатает действующие значения и источник каждого. Значения в таблицах ниже —
**умолчания**; если вывод расходится с ними, считай по выводу. Последняя строка вывода —
готовое поле `config=...` для записи `scope`: **перенеси её дословно**, валидатор
пересчитывает эту отметку сам и написанное по памяти отвергает. Почему именно так —
`references/profile-axes.md`.
### Ось 1: объём (скаляр)
Что тронуто и пересекает ли правка границы.
| Класс | Признаки |
|---|---|
| **C0** Косметика | комментарии, форматирование, переименование без смены семантики; тела методов не менялись |
| **C1** Точечная | файлов ≤ `volume.c1MaxFiles` (умолчание 1), изменённых строк ≤ `volume.c1MaxLines` (умолчание 40), правка внутри существующих методов; нет новых экспортов, изменённых сигнатур, новых модулей и объектов метаданных |
| **C2** Модульная | >1 метода, ИЛИ новый экспортный метод, ИЛИ изменена сигнатура, ИЛИ превышен порог строк либо файлов — в пределах существующих модулей |
| **C3** Структурная | новый модуль / объект метаданных / форма, ИЛИ изменение проведения и бизнес-логики, ИЛИ новая интеграция, ИЛИ затронуто ≥4 модуля разных подсистем |
Источник данных: `git diff --stat` и `git diff` по рабочему дереву, либо явно названные
пользователем файлы. Состав правки — из `node "$QG/tools/gate.mjs" status`.
### Ось 2: архетипы кода (множество меток)
**Объёма недостаточно: три строки внутри транзакции опаснее трёхсот строк переименований.**
Архетипы не упорядочены и комбинируются — одна правка может быть одновременно «запросом»,
«транзакцией» и «интеграцией». Определяются механически по маркерам в диффе и путям файлов.
| Архетип | Метка в следе | Маркер в диффе | Мин. `code` | Мин. `arch` |
|---|---|---|---|---|
| Запрос | `query` | `Новый Запрос`, правка текста запроса | L2 | — |
| Транзакция, блокировки | `transaction` | `НачатьТранзакцию`, `Заблокировать` | L2 | — |
| Запись наборов записей | `record-set` | `Записать(Истина)`, `СоздатьНаборЗаписей` | L2 | — |
| Обработчик события объекта | `object-event` | `ПередЗаписью`, `ПриЗаписи`, `ОбработкаПроведения` | L2 | ур. 1 |
| Интеграция, HTTP | `integration` | `HTTPСоединение`, `WSПрокси`, `Новый COMОбъект` | L2 | ур. 1 |
| Права, RLS | `rights` | XML ролей, `УстановитьПривилегированныйРежим` | L2 | ур. 2 |
| CFE-перехват | `cfe-patch` | `&Перед`, `&После`, `&Вместо`, `&ИзменениеИКонтроль` | L2 | ур. 1 |
| Регламентное, фоновое | `scheduled-job` | подписка регл. задания, `ФоновыеЗадания` | L2 | — |
| Клиент-сервер | `client-server` | директивы компиляции | L1 | **ур. 1** |
| **Диалог посреди логики** | `user-dialog` | `ПоказатьВопрос`, `ВопросАсинх`, `ОповещениеОЗавершении` | L1 | **ур. 1** |
| Модуль формы | `form-module` | путь `Forms/*/Module.bsl` | L1 | ур. 1 при `loc > 400` |
| Асинхронный клиент | `async-client` | `Асинх`, `Ждать`, `Обещание` | L1 | — |
| **Новый общий модуль** | `new-common-module` | новый файл `CommonModule` | L1 | **ур. 2** |
| **Новый объект метаданных** | `new-metadata-object` | новый XML в `src/` | L1 | **ур. 3** |
Обязательные чеклисты по каждому архетипу перечисляет контур в своём SKILL.md: продублируй
их здесь — и они разъедутся с тем, что контур делает на самом деле.
**Колонка «Метка в следе» — ровно то, что пишется в поле `archetypes` записи `scope`.** Метка
не переводится и не сокращается: `queries` вместо `query` означает не «почти то же самое», а
«правило не сработало», и снятие гейта валидатор не пропустит. Свои архетипы проект заводит
в секции `archetypes.custom` (имя, маркеры, `minCode`, `minArch`), их имена — тоже законные
метки. Почему минимумы по двум контурам асимметричны — `references/profile-axes.md`.
### Ось 3: сложность (скаляр)
Закрывает случай «мало строк, но код тяжёлый», когда архетипа может не быть вовсе.
Считается по изменённым методам: вложенность ≥ `complexity.maxNesting` (4), длина метода
> `complexity.maxMethodLines` (120), параметров ≥ `complexity.maxParams` (7), цепочка
ветвлений ≥4, рекурсия. Срабатывание поднимает `code` до L2 и `arch` до уровня 1.
Метрики — из отчёта `tools/analyzer-run.mjs --json` (`functions`, `complexity`,
`cognitive_complexity`), считать самому не нужно. Анализатор запускается **с гейтовым
конфигом из состава плагина**: проектный может отсечь изменённые файлы фильтром подсистем и
оставить правдоподобно пустой отчёт (`references/profile-axes.md`).
### Итог: правило разрешения
> **глубина контура = max(по объёму, максимум минимумов по сработавшим архетипам, по сложности)**
Отдельно фиксируется **`driver`** — что именно подняло глубину: объём, конкретный архетип
или сложность. Без него вердикт виден, а логика нет, и первое же «почему так долго на трёх
строках?» превращается в спор.
### Понижающий модификатор: эталонная правка
Понижает глубину до C1 независимо от объёма, если выполнены **три условия сразу**:
(а) все фрагменты — кальки типового эталона того же механизма с точечной адаптацией имён и
полей; (б) уже прошли предметный верификатор механизма с нулём ошибок; (в) не трогают
транзакции, блокировки и права. Хотя бы одно не выполнено — модификатор не применяется.
---
## Шаг 2. Матрица глубин по объёму (базовый уровень)
| Контур | C0 | C1 | C2 | C3 |
|---|---|---|---|---|
| `hygiene` | полный | полный | полный | полный |
| `code` | пропуск | L1 | L1 + L2 | L1 + L2, предложить аудит |
| `arch` | пропуск | пропуск | ур. 1–2 | ур. 3 |
| `xml` | пропуск | не применим, если XML не менялся | изменённые объекты + **регистрация** | полный: валидация + сироты в обе стороны + права ролей |
| компилируемость | — | если платформа доступна | да | да |
`hygiene` гоняется всегда: стоимость околонулевая, а ловит он то, что проявляется позже
всего и объясняется хуже всего. Разовое отклонение от расчётной глубины — `--deep` /
`--quick`.
---
## Шаг 3. Прогон контуров
Запускай только те контуры и глубины, которые дал шаг 2. Каждый контур обязан вернуть
запись `applied` либо `skipped` — **молчание не допускается**.
| Контур | Навык | Состояние |
|---|---|---|
| `code` | `bsl-code-review` — стандарты, антипаттерны, верификация API | готов |
| `arch` | `bsl-architecture-review` — принципы, паттерны, границы модулей | готов |
| `xml` | `xml-structure-review` — структура метаданных, регистрация, права | готов |
| `hygiene` | `file-hygiene` — кодировки, BOM, символы, переводы строк | готов |
Передавай контуру профиль целиком: класс, сработавшие архетипы, список изменённых файлов.
Пересчитывать профиль контур не должен — иначе оси разъедутся и решение о глубине перестанет
быть проверяемым.
### Контур исполняется вызовом навыка, а не по памяти
Таблица называет навыки, а не проверки: чем именно проверяется признак, написано в SKILL.md
контура. Прогон без открытия навыка воспроизводит контур как чеклист для чтения глазами —
вердикт выглядит результатом проверки, но им не является, и происходит это не по
небрежности (`references/run-environment.md`).
**У части проверок есть исполняемый инструмент. Для них строку следа печатает сам
инструмент** — не сочиняй её. Прогон отмечается в журнале (`qg-runs.jsonl` в каталоге
состояния гейта: `.claude/.state/` в Claude Code, `.opencode/.state/` в OpenCode)
вместе с путями файлов, и валидатор сверяет по нему каждую запись `applied`: и то, что
инструмент запускался, и то, что он видел **весь** состав правки. Прогон по одному файлу из
десяти заявление обо всех десяти не закрывает; `skipped ... reason=not_applicable` — тоже
утверждение о работе инструмента.
Гонять инструмент по частям можно, прогоны складываются: передавай все изменённые файлы его
вида, список даёт `gate.mjs status`. **`query-lint` принимает не только `.bsl`** — он читает
`<query>` схем компоновки и `<QueryText>` динамических списков, поэтому изменённые XML идут
и в него.
| Проверка (`scope`) | Инструмент |
|---|---|
| `static-analysis` | `tools/analyzer-run.mjs` |
| `query-alias-shadowing`, `query-top-order` | `tools/query-lint.mjs` (`.bsl` и `.xml`) |
| `transaction-nesting`, `enum-string-assign`, `unbounded-string-column`, `attribute-access` | `tools/bsl-lint.mjs` |
| `stale-local-calls` | `tools/rename-check.mjs` |
| `file-encoding` | `tools/hygiene-check.mjs` |
| `registration-check` | `tools/xml/orphan-check.mjs` |
| `uuid-uniqueness` | `tools/xml/uuid-unique.mjs` |
| `structure-validation` | `tools/xml/meta-validate.py` |
| `form-binding` | `tools/xml/form-validate.py` |
Остальные проверки (архитектурные признаки, разбор стандартов, верификация API) инструмента
не имеют: журнала для них не требуется. Полный словарь имён — `tools/evidence-scopes.mjs`;
имя вне словаря валидатор отвергает, потому что закрывает требование, которого не выполняло.
### Субагенты в составе прогона
Три штатных, все дешёвые и **только читающие**. Записи следа они не пишут: агент возвращает
факты, запись формирует контур.
| Субагент | Кем вызывается | Зачем | Спавнов |
|---|---|---|---|
| `bsl-verifier` | контур `code`, верификация API | сигнатуры платформы, экспортность общих модулей, состав метаданных | один на весь список файлов |
| `bsl-scout` | контур `arch`, признаки по графу вызовов | вызывающие, экспорты модуля, триггеры в XML | один на вопрос, независимые — параллельно |
| `xml-runner` | контур `xml` | сверка «диск ↔ состав», валидаторы структуры, разбор их вывода | один на прогон контура |
Недоступность субагента, контура или инструмента проверку не отменяет: она выполняется сама
либо получает `skipped` с точной причиной. Границы применения и список причин деградации —
`references/run-environment.md`.
**Перед повторным прогоном слоя проверь `gate.mjs status`:** слой, уже отработавший по этому
содержимому, пропускается с причиной `verified_earlier`, а любая правка файла снимает его
отметку. Механика — `references/evidence-format.md`.
---
### Слой 3 контуров: состязательный аудит
Самая дорогая проверка и единственная, которая **никогда не запускается сама**. Контуры
предлагают её в отчёте при классе C3 с находками 🔴 или 🟠; запуск — только после явного
согласия пользователя. Методология, пороги и поведение при недоступной оркестрации —
в `references/adversarial-audit.md`.
---
## Шаг 4. Sentinel — проверка живости источника стандартов
Один раз за прогон запроси через MCP `v8std` заведомо существующий стандарт — тот, чей номер
задан в `sentinel.id` проектной настройки (умолчание `std454`, фактическое значение — в
выводе `config.mjs show` из шага 1): `v8std_get_page("<sentinel.id>")`. Ожидание — страница
найдена.
Без этой проверки «нарушений стандартов не найдено» неотличимо от «сервис стандартов
недоступен»: неподтверждённый часовой делает прогон недостоверным, и валидатор следа
отклонит снятие гейта. Почему номер вынесен в настройку — `references/run-environment.md`.
---
## Шаг 5. Отчёт и след
Отчёт для человека — находки по severity (🔴 Critical / 🟠 Major / 🟡 Minor) в формате
контура. Ниже, в секции `## quality evidence`, — машиночитаемый след: одна строка на
проверку. Формат, полный список причин и правила валидатора — `references/evidence-format.md`.
**Каждая запись `not_verified` повторяется в человекочитаемой части одной фразой.** «Ошибок: 0»
рядом с невидимым `not_verified` читается как «проверено» — измерено на живом разборе: так
дважды возникла ложная уверенность в проверенности запроса. Фраза короткая и по делу:
«текст запроса статически чист; выполнимость не проверялась — платформы нет».
Обязательный минимум следа: одна запись `scope` (с полем `config` из шага 1), одна
`sentinel`, по записи от каждого запущенного или пропущенного контура, и — если
компилируемость тел модулей не проверялась — запись `not_verified: dimension=compilation`.
Компилируемость не проверяется ничем, кроме платформы, поэтому полностью зелёный отчёт без
такой записи валидатор отклоняет.
**Сработал архетип «Запрос» — выполни запрос до вердикта:** в консоли запросов, на тестовых
параметрах, прогоном обработки. Для всех инструментов текст запроса остаётся строковым
литералом, и «Неоднозначное поле» доживает до продуктива. Выполнить негде — законный исход,
но записанный:
```
[qg applied: layer=code, scope=query-execution, ids=[qg:QRY-EXECUTED], verdict=clean]
[qg not_verified: dimension=query-execution, reason=no_platform]
```
**Изменённый файл, до которого не добрался анализатор, не проверен.** `analyzer-run.mjs`
считает такие файлы и печатает запись сам — переноси её дословно; число непроверенных
уходит в журнал, и промолчать о них валидатор не даст.
Проверить след перед снятием:
```bash
node "$QG/tools/evidence-validator.mjs" <файл отчёта> --gate
```
---
## Шаг 6. Снятие гейта
Гейт снимается **только** утилитой — не удалением файла состояния вручную:
```bash
# по результатам прогона (след проверяется, дефектный след снятие не пропустит)
node "$QG/tools/gate.mjs" release --evidence <файл отчёта>
# правка не требует проверки — допустимо только для C0/C1, причина обязательна
node "$QG/tools/gate.mjs" release --class C0 --reason "<почему>"
```
НЕ снимай гейт, если прогон прерван на полпути и отчёт не сформирован: гейт должен
остаться, чтобы проверка прогналась заново.
**Чужие сессии не трогай.** Состояние гейта разделено по сессиям: если `gate.mjs status`
показывает несколько, снимай свою, указав `--session <id>` — идентификатор печатается в
сообщении о блокировке (`references/run-environment.md`).
---
## Путь к инструментам плагина (`$QG`)
Все команды выше используют `$QG` — каталог установленного плагина. Под OpenCode он приходит
готовым в `QG_ROOT`: плагин отдаёт корень пакета в окружение каждого запуска оболочки.
В Claude Code такой переменной нет — **`CLAUDE_PLUGIN_ROOT` доступна хукам, но не оболочке**,
в шелле она пуста, и путь `"${CLAUDE_PLUGIN_ROOT}/tools/..."` схлопнулся бы в `/tools/...`.
Разреши путь **первой командой прогона** и дальше подставляй полученное значение буквально
(состояние оболочки между вызовами не сохраняется). **Каждый кандидат принимается только
после проверки `test -d "$QG/tools"`**: существование переменной или каталога ещё не значит,
что там лежит этот плагин — установка могла быть частичной, устаревшей или чужой.
```bash
QG="${QG_ROOT:-}"
[ ! -d "$QG/tools" ] && QG="${CLAUDE_PLUGIN_ROOT:-}"
[ ! -d "$QG/tools" ] && QG="$(node -e "const p=require(require('node:os').homedir()+'/.claude/plugins/installed_plugins.json').plugins;const k=Object.keys(p).find(n=>n.startsWith('1c-quality-gate@'));if(k&&p[k][0])process.stdout.write(p[k][0].installPath)" 2>/dev/null)"
[ ! -d "$QG/tools" ] && QG="$(ls -d ~/.claude/plugins/cache/*/1c-quality-gate/*/ 2>/dev/null | sort -V | tail -1)" && QG="${QG%/}"
test -d "$QG/tools" && echo "$QG" || { echo "Плагин не найден ни в одном харнессе" >&2; exit 1; }
```
`sort -V` не декоративен: без него сессия работает инструментами устаревшей версии и честно
отчитывается, что проверок «не существует». Разбор — `references/run-environment.md`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!