quality-gate · diff
git:20260920.b96dd1b to git:20260920.73a9f98
18 added, 18 removed. Audit A to A.
---
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`, а не удалением файла состояния.
- 9. **План печатает `gate.mjs plan`**; модель вправе поднять глубину с причиной, понизить —
+ 9. **План считает и исполняет `gate.mjs run`**; модель вправе поднять глубину с причиной, понизить —
нет.
---
## Шаг 1. План
### Путь к инструментам плагина (`$QG`)
Все команды ниже используют `$QG` — каталог плагина. Под OpenCode он готов в `QG_ROOT`; в
Claude Code `CLAUDE_PLUGIN_ROOT` оболочке не видна — путь схлопнулся бы в `/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; }
+ test -d "$QG/tools" || { echo "Плагин не найден ни в одном харнессе" >&2; exit 1; }
+ node "$QG/tools/gate.mjs" run
```
`sort -V` обязателен: без него берётся устаревшая версия плагина
(`references/run-environment.md`).
- ### Профиль и план прогона
-
- ```bash
- node "$QG/tools/gate.mjs" plan --files <f> [<f> ...] [--no-analyzer]
- ```
+ ### Профиль и инструменты — той же командой
- Без `--files` — состав из взведённой сессии (`gate.mjs status`). Печатает профиль по трём
- осям, строку `scope` (с `config=...`), инструменты по порядку, что закрыть в следе.
- `--no-analyzer` — когда анализатор недоступен или падает; ось сложности тогда `not_computed`,
- `driver` не бывает `complexity:*`.
+ Последняя строка блока — `gate.mjs run [--files <f> ...] [--only <инструмент,...>]
+ [--no-analyzer]`: поиск пути и прогон занимают один ход. Без `--files` — состав из взведённой
+ сессии (`gate.mjs status`). Печатает `QG=<путь>` для следующих команд, профиль, строку
+ `scope` (с `config=...`), сводку инструментов, вывод тех, у кого находки и сбои, черновик
+ следа и что осталось модели. Полный вывод, сравнение версий и индекс каталога — в каталоге
+ прогона, не в контексте. `--no-analyzer` — когда анализатор недоступен или падает; ось
+ сложности тогда `not_computed`.
**Строку `[qg scope: ...]` перенеси в отчёт дословно** — валидатор пересчитывает профиль сам.
Расхождение — сверь порог: `node "$QG/tools/config.mjs" show`. **Профиль можно поднять,
нельзя понизить**: увидел то, чего план не видит (правка тише архетипа, но трогает деньги) —
подними, добавь «глубина поднята: <причина>»; обратное валидатор не пропустит.
Почему оси устроены так — `references/profile-axes.md`; данные — `tools/profile.mjs`,
`tools/gate.mjs`.
---
## Шаг 2. Инструменты
- Выполни команды раздела «## Инструменты» плана по порядку — файлы уже подставлены. У части
- есть исполняемый инструмент: он печатает строку следа (`[qg applied: ...]` / `[qg skipped:
- ...]`) сам — переноси дословно, не сочиняй.
+ Их исполнил `run`. Строки следа печатают сами инструменты — переноси черновик дословно, не
+ сочиняй. **СБОЙ** в сводке: строки за упавший инструмент нет — перезапусти его (`--only`) либо
+ закрой `skipped` с причиной. После правки кода повтори `run`. `platform-context-run.mjs` обязателен и при `--only`:
+ анализатор знает имена конфигурации, но не платформы. Субагентам называй каталог
+ прогона: готовый вывод они читают оттуда, а не гоняют инструменты заново.
Прогон отмечается в журнале `qg-runs.jsonl`: валидатор сверяет по нему каждую запись
- `applied` — инструмент видел **весь** состав правки, а не файл из десяти; `skipped ...
- reason=not_applicable` — тоже утверждение о работе. Прогоны по частям складываются.
- `platform-context-run.mjs`, когда включён планом, обязателен: анализатор знает имена
- конфигурации, но не платформы. `query-lint` берёт и изменённые XML, не только `.bsl`.
+ `applied` — инструмент видел **весь** состав правки; `skipped ... reason=not_applicable` —
+ тоже утверждение о работе. Прогоны по частям складываются.
**Перед повторным прогоном слоя проверь `gate.mjs status`:** отработавший по этому
содержимому слой пропускается с причиной `verified_earlier` (`references/evidence-format.md`).
---
## Шаг 3. Контуры
Запускай контуры и глубины из `resolved: code=... arch=... xml=... hygiene=...` плана.
Каждый контур обязан вернуть `applied` либо `skipped` — **молчание не допускается**.
| Контур | Навык |
|---|---|
| `code` | `bsl-code-review` |
| `arch` | `bsl-architecture-review` |
| `xml` | `xml-structure-review` |
| `hygiene` | `file-hygiene` |
Передавай контуру профиль целиком: класс, архетипы, файлы.
### Контур исполняется вызовом навыка, а не по памяти
Таблица называет навыки, а не проверки: чем проверяется признак — в SKILL.md контура. Прогон
без открытия навыка — чеклист для чтения глазами, не проверка
(`references/run-environment.md`).
### Субагенты в составе прогона
**Только читающие**: возвращают факты, запись формирует контур. Дешёвые, кроме
`antipattern-reader` и `cold-reader`: семантика и суждение до haiku не сводятся.
| Субагент | Вызывает | Факты | Спавнов |
|---|---|---|---|
| `bsl-verifier` | `code` | сигнатуры платформы, экспортность модулей, метаданные | на файлы |
| `antipattern-reader` | `code` | кандидаты с цитатами; аттестует `tools/catalog.mjs` | на контур |
| `cold-reader` | `code` | слой 2: чтение без замысла | на контур |
| `bsl-scout` | `arch` | вызывающие, экспорты, триггеры XML | по вопросу |
| `xml-runner` | `xml` | «диск ↔ состав», валидаторы структуры | на контур |
Недоступность субагента, контура или инструмента проверку не отменяет — она проходит сама
либо получает `skipped` с причиной (`references/run-environment.md`).
---
### Слой 3: состязательный аудит
Самая дорогая проверка, никогда не запускается сама: контуры предлагают её при классе C3 с
находками 🔴/🟠, запуск — только по явному согласию пользователя
(`references/adversarial-audit.md`).
---
## Шаг 4. Sentinel — проверка живости источника стандартов
Один раз за прогон запроси через MCP `v8std` стандарт, чей номер — `sentinel.id` настройки
(умолчание `std454`): `v8std_get_page("<id>")`, ожидание — страница найдена.
Без неё «нарушений не найдено» неотличимо от «сервис недоступен»: неподтверждённый часовой
делает прогон недостоверным (`references/run-environment.md`).
---
## Шаг 5. Отчёт и след
Отчёт для человека — находки по важности (🔴 Critical / 🟠 Major / 🟡 Minor). Ниже, в
`## quality evidence`, — машиночитаемый след: строка на проверку
(`references/evidence-format.md`).
**Каждая запись `not_verified` повторяется в человекочитаемой части фразой**: «Ошибок: 0»
рядом с невидимым `not_verified` читается как «проверено».
Минимум следа: `scope` (Шаг 1), `sentinel` (Шаг 4), запись от каждого контура и всё из плана
«Закрыть в следе» — включая `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 <файл отчёта> # по результатам прогона
node "$QG/tools/gate.mjs" release --class C0 --reason "<почему>" # C0/C1 без прогона
```
Отчёт — во временный каталог, не в проект: `release` копирует его в архив вне git;
ссылайся на путь `Копия отчёта:` (`references/run-environment.md`).
НЕ снимай гейт, если прогон прерван на полпути и отчёт не сформирован: он должен остаться
для повторной проверки.
**Чужие сессии не трогай.** Гейт разделён по сессиям: несколько в `gate.mjs status` —
`verify`/`release` без `--session <id>` отказывают, «самая свежая» может быть чужой.
Идентификатор — в подсказке при взводе и в сообщении о блокировке
(`references/run-environment.md`).