Контур проверки кода BSL: диагностики статического анализатора, антипаттерны производительности и механики платформы, стандарты разработки #stdNNN, именование, верификация сигнатур API и существования общих модулей. Уровень «внутри тела метода» — то, что чинится заменой строк. Вызывается оркестратором quality-gate с готовым профилем изменения; напрямую — по запросу «проверь код», «отревьюй что я написал», «проверь на антипаттерны».
Scanned 8/30/2026
Install to Claude Code
npx -y skills add Romandredan/1c-quality-gate --skill bsl-code-review --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Bsl Code Review?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/romandredan-bsl-code-review)More formats (shields.io, HTML) on the badges page.
---
name: bsl-code-review
description: >-
Контур проверки кода BSL: диагностики статического анализатора, антипаттерны производительности
и механики платформы, стандарты разработки #stdNNN, именование, верификация сигнатур API и
существования общих модулей. Уровень «внутри тела метода» — то, что чинится заменой строк.
Вызывается оркестратором quality-gate с готовым профилем изменения; напрямую — по запросу
«проверь код», «отревьюй что я написал», «проверь на антипаттерны».
license: MIT
---
# bsl-code-review — контур кода
Проверяет то, что чинится **внутри тела метода**: замена строк, без нового шва. Всё, что
требует выделения метода, переноса в другой модуль, нового экспорта или изменения «кто кого
вызывает», принадлежит контуру `bsl-architecture-review` — граница и правила дедупликации
находок в `shared/routing-contract.md`.
<ЖЁСТКИЙ-ШЛЮЗ>
Только проверка и отчёт. НЕ переписывай логику, запросы, транзакции и права по своей
инициативе. В режиме `--fix` допустимы лишь безопасные категории (см. ниже).
</ЖЁСТКИЙ-ШЛЮЗ>
## Инварианты контура
Пять утверждений, без которых прогон контура недействителен.
1. **Оба файла антипаттернов прогоняются всегда** — и на мелкой правке тоже. Находка 🔴 из
любого блокирует вердикт «чисто».
2. **Строку следа инструментальной проверки печатает инструмент** — переноси дословно,
своих находок этого класса не добавляй: результат детерминирован.
3. **Каждое замечание доказуемо**: номер стандарта, код диагностики или название
антипаттерна плюс строка кода. «Так лучше» — не находка.
4. **Пропуск фиксируется.** Недоступный инструмент или субагент даёт `skipped` с причиной;
молчание неотличимо от выполнения.
5. **Файл, который анализатор не разобрал, не проверен** — вердикт «чисто» по нему
невозможен, и в отчёте он назван поимённо.
## Вход
От оркестратора: класс изменения (C0…C3), сработавшие архетипы, список изменённых файлов.
При прямом вызове — определи профиль сам по правилам `quality-gate`.
| Класс | Глубина |
|---|---|
| C0 | контур не запускается |
| C1 | Слой 1 |
| C2 | Слой 1 + Слой 2 |
| C3 | Слой 1 + Слой 2, предложить Слой 3 |
Архетип поднимает глубину независимо от класса: запрос, транзакция, запись наборов записей,
обработчик события объекта, интеграция, права, CFE-перехват, регламентное задание — минимум
Слой 2. Итоговая глубина — максимум из требований объёма, архетипов и сложности.
---
## Слой 1а — статический анализ
Одна команда: она находит корень конфигурации, прогоняет только изменённые файлы, проверяет
часового и формирует записи следа.
```bash
node "$QG/tools/analyzer-run.mjs" --changed <файл> [--changed <файл> ...]
```
Вывод — находки по файлам и готовый блок `## quality evidence`. Перенеси его в отчёт как
есть: записи следа по слою `code` сочинять руками не нужно и нельзя.
**Твоя работа здесь — триаж, а не припоминание.** Список нарушений детерминирован. От тебя
требуется отделить то, что надо чинить сейчас, от того, что является осознанной нормой этого
проекта, и назвать последствие каждой оставленной находки. Коды расшифровывай через
`v8std_explain_diagnostics` и привязывай к номеру стандарта.
Четыре режима вывода, каждый из которых меняет то, что можно утверждать по результату:
- **Информационные находки свёрнуты** в одну строку, полный список — флаг `--all`. В след
коды попадают в любом случае.
- **Проект без основной конфигурации** (репозиторий одного расширения): диагностики о
неразрешённых именах понижены до информационных — обратно **не поднимай**, отличить их от
настоящих ошибок в этом режиме нечем.
- **«НЕ РАЗОБРАНО файлов»** — по этим файлам не проверено **ничего**. Назови их в отчёте
поимённо: вердикт «чисто» по ним невозможен.
- **Часовой `status=not_found`** — прогон недостоверен, вердикт «чисто» запрещён; разберись
с анализатором и повтори.
Что стоит за каждым режимом и известные случаи — `references/analyzer-output.md`. Гейтовый
анализ идёт с конфигом из состава плагина: проектный `subsystemsFilter` вывести изменённые
файлы из проверки не может.
**Если анализатор недоступен** — команда сама запишет
`[qg skipped: layer=code, scope=static-analysis, planned=[bslls:*], reason=analyzer_unavailable]`
и вернёт код 1. Продолжай со Слоя 1б: он ловит другое и от анализатора не зависит.
## Слой 1б — то, чего анализатор не видит
### 1. Антипаттерны производительности и механики платформы
Источник: `references/bsl-anti-patterns.md` — прогоняется **всегда**, при любой глубине.
| Антипаттерн | Что искать | Severity |
|---|---|---|
| Запрос в цикле | `Новый Запрос` внутри `Для Каждого` | 🔴 |
| Чтение реквизита через точку | `.Реквизит` у ссылочного типа — грузит объект целиком | 🔴 |
| Подзапрос в списке полей | вложенный `ВЫБРАТЬ` в секции выборки (N+1) | 🔴 |
| Коррелированный подзапрос в условии | вложенный `ВЫБРАТЬ` в `ГДЕ`, ссылающийся на внешнее поле | 🔴 |
| Фильтр виртуальной таблицы в ГДЕ | условие на результате ВТ вместо её параметров | 🟠 |
| Временная таблица без индекса | `ПОМЕСТИТЬ` без `ИНДЕКСИРОВАТЬ ПО`, далее соединение по этому полю | 🟠 |
| Отсутствие ограничения выборки | большой запрос без `ПЕРВЫЕ N` | 🟠 |
| Множественные серверные вызовы | последовательные вызовы сервера с клиента | 🟠 |
| Контекстный вызов без нужды | `&НаСервере` там, где хватает `&НаСервереБезКонтекста` | 🟠 |
| Транзакция внутри Попытки | `НачатьТранзакцию()` внутри `Попытка`, а не наоборот | 🟠 |
| Транзакция внутри неявной транзакции | `НачатьТранзакцию()` в `ОбработкаПроведения`, `ПередЗаписью`, `ПриЗаписи` | 🟠 |
| `Сообщить()` как уведомление | сообщение без привязки к объекту и вне журнала регистрации | 🟠 |
| Отсутствие кеширования | повторные дорогие вызовы с теми же параметрами | 🟡 |
| Квадратичный поиск | вложенные циклы сопоставления вместо `Соответствие` | 🟡 |
### 2. Антипаттерны кода, порождаемого моделью
Источник: `references/ai-antipatterns.md` — прогоняется **всегда, наравне с предыдущим**.
Типовые своды описывают ошибки, которые делают люди. Этот файл — про ошибки, характерные
для кода, написанного языковой моделью: перепроверка контракта собственной функции, форк
парсера на каждый вариант ответа, отчёт о непрогнанной проверке. Ни один типовой свод их не
покрывает, потому что человек их обычно не делает.
### 3. Лексические проверки инструментами
```bash
node "$QG/tools/query-lint.mjs" <файл.bsl|файл.xml> [<файл> ...]
node "$QG/tools/bsl-lint.mjs" <файл.bsl> [<файл.bsl> ...]
node "$QG/tools/rename-check.mjs" <файл.bsl> [<файл.bsl> ...]
python "$QG/tools/xml/form-validate.py" -Path <Form.xml> # правился модуль формы
```
`query-lint` читает и XML-носители запросов — `<query>` схем компоновки данных и
`<QueryText>` динамических списков, — поэтому **изменённые XML передаются ему наравне с
модулями**; номер строки в такой находке считается от начала текста запроса, как в
сообщениях платформы. Оба инструмента печатают готовые записи следа и отмечаются в журнале
прогонов.
| Признак | Sev | Что ловит | Разбор |
|---|---|---|---|
| `qg:QRY-ALIAS-SHADOWS-FIELD`, `qg:QRY-ALIAS-SHADOWS-NESTED-TABLE` | 🔴 / 🟠 | псевдоним совпал с именем колонки ВТ пакета или табличной части, чей владелец в той же ветке: «Неоднозначное поле». Разыменование — 🔴, без обращения через точку — 🟠 | `references/bsl-query-reference.md` |
| `qg:QRY-TOP-WITHOUT-ORDER` | 🟡 | `ПЕРВЫЕ N` без `УПОРЯДОЧИТЬ ПО` — набор строк недетерминирован | `references/bsl-anti-patterns.md` п. 5 |
| `qg:BSL-TXN-IN-HANDLER` | 🟠 | своя `НачатьТранзакцию` внутри обработчика, который платформа уже выполняет в транзакции (#std783 п. 1.4) | `references/bsl-anti-patterns.md` п. 8б |
| `qg:BSL-ENUM-STRING-ASSIGN` | 🟠 | примитив в поле строго ссылочного типа: сборка молчит, падает при записи | `references/bsl-anti-patterns.md` п. 8в |
| `qg:BSL-STALE-LOCAL-CALL` | 🔴 | вызов метода, чьё объявление было в HEAD и исчезло в правке: переименование не доведено до точек вызова | `references/bsl-anti-patterns.md` п. 8г |
| `qg:BSL-UNBOUNDED-STRING-COLUMN` | 🟠 | строковая колонка без квалификатора у таблицы, уходящей в параметр запроса (#std432 п. 3.1) | `references/ai-antipatterns.md`, `qg:AI-16` |
| `qg:BSL-REF-DOT-ACCESS` | 🔴 / 🟠 | обращение к реквизиту ссылки через точку: объект читается целиком ради одного поля (#std437). Ссылочность доказывается присваиванием в методе или типом параметра из описания #std453 (🟠 — описание могло устареть), либо именем на «Ссылка» | `references/bsl-anti-patterns.md` п. 2 |
**`attribute-access` покрыт инструментом лишь частично.** Доказать ссылочность в пределах
одного файла удаётся не всегда: ссылка из чужой функции или из недокументированного параметра
остаётся неопознанной. `clean` здесь означает «механическая часть чиста» и разбора #std437
глазами не отменяет — инструмент задаёт нижнюю границу, а не верхнюю.
**Записи переносятся дословно, своих находок этого класса не добавляй.** Результат
детерминирован, а строка, составленная по прочтении кода, выглядит в отчёте точно так же —
поэтому валидатор следа её отвергает.
Оба инструмента видят один файл и графа вызовов не строят, а запрос, собранный конкатенацией
или `СтрШаблон`, виден им лишь частями. Эти области остаются непроверенными, и вердикт
«чисто» по инструменту их не закрывает — разбор приближений у каждого правила в его
справочнике.
### 4. Стандарты под архетип
Не весь свод подряд — только релевантное:
| Архетип | Справочники |
|---|---|
| Запрос | `bsl-query-optimization.md`, `bsl-query-reference.md` |
| Модуль формы | `bsl-form-module-rules.md` |
| Асинхронный клиент | `bsl-async.md` |
| Новый модуль, форматирование, транзакции | `bsl-coding-standards.md` |
| Кастомная утилита | `bsp-common-modules.md` — есть ли готовый метод библиотеки |
| Глубокая вложенность, длинные методы | `bsl-refactoring.md` |
Плюс `references/checklist-code.md` — 17 разделов по областям; бери разделы под затронутый
архетип. Тексты самих стандартов запрашивай через MCP `v8std` по номеру.
### 5. Именование
`#std454` — частая и легко пропускаемая ошибка: сокращения-префиксы, не-CamelCase,
булево не в утвердительной форме. Детали и примеры — в `references/checklist-code.md`.
### 6. Символы в исходнике
В коде и комментариях только ASCII-дефис. Длинное тире и его родственники дают у анализатора
ошибку недопустимого символа. Кавычки-ёлочки допустимы.
### 7. Верификация API — субагент `bsl-verifier`
Сигнатуры платформенных методов, существование и экспортность общих модулей, состав объектов
метаданных. Процедура — `references/api-verification.md`.
**Делегируй субагенту `bsl-verifier`**, передав ему список изменённых `.bsl`-файлов. Он
дешёвый, работает по той же процедуре и возвращает вердикт, список нарушений с локациями и
раздел «Не проверено». Вызов **один на весь список**: справочник платформы не терпит
параллельных обращений, а каждый лишний инстанс поднимает свою сессию индекса кода.
Субагента в среде может не быть — тогда прогоняй `api-verification.md` сам. **Результат
обязан попасть в след одинаково в обоих случаях** (инвариант 4):
```
[qg applied: layer=code, scope=api-verification, ids=[qg:API-SIGNATURE,qg:API-MODULE], verdict=clean]
[qg skipped: layer=code, scope=api-verification, reason=platform_unavailable]
```
> Для класса C1 на этом контур завершается — переходи к отчёту.
---
## Слой 2 — ревью логики моделью
Вызови `advisor()`. Более сильная модель видит весь транскрипт: задачу, шаги, написанный код.
Ловит то, что статика не видит в принципе — неверную бизнес-логику, упущенные сценарии,
неучтённые состояния. Замечаниям давай весомый вес.
### Холодный читатель — второй взгляд с противоположным входом
Дополнительно к `advisor()`, когда цена ошибки высока: класс C3 либо затронуты проведение,
деньги, права, необратимые операции. Ценность даёт противоположность входов: `advisor()` видит
всё и ловит «сказал одно, написал другое», холодный читатель не видит ничего, кроме кода, и
потому читает его без достройки смысла из намерения.
**Передавать:** только дифф и содержимое изменённых файлов. **Не передавать:** формулировку
задачи, свои выводы, названия уже найденных проблем — узнав намерение, он перестаёт быть
холодным и превращается во второй `advisor()`, только слабее.
Три вопроса, на которые он отвечает:
1. Что этот код делает **как написан**, а не как задуман?
2. На каких входных данных он ломается или ведёт себя неожиданно?
3. Какое ожидаемое поведение из него не следует?
**Модель — не дешёвая:** здесь выносится суждение о логике, уровень нужен не ниже основной
модели сессии. Расхождение его выводов с `advisor()` — сигнал, а не шум: код допускает два
прочтения. Разбор — `references/cold-reader.md`.
## Слой 3 — состязательный аудит (только по подтверждению)
**Никогда не запускается сам** — контур лишь предлагает его в отчёте и ждёт явного согласия.
Суть: веер независимых ревьюеров по измерениям (корректность механики платформы, запросы,
транзакции, события объектов, клиент-сервер, безопасность, антипаттерны модели), затем по
каждой находке несколько проверяющих, которым поставлена задача её **опровергнуть**. Проходит
только то, что опровергнуть не удалось.
Пороги, правила голосования, асимметрия для находок 🔴 и порядок действий, когда оркестрация
недоступна, — в `../quality-gate/references/adversarial-audit.md`.
---
## Автофикс (`--fix`)
**Можно:** именование (через переименование символа анализатором, не текстовой заменой),
форматирование и отступы, канонические ключевые слова, магические литералы на системные
константы, очевидные quick-fix анализатора.
**Нельзя без подтверждения:** любая правка логики, проведения, запросов; транзакции и
блокировки; права и привилегированный режим; всё, помеченное 🔴; сигнатуры экспортных методов
(ломает вызывающих).
После автофикса прогони Слой 1 заново — правки могли внести новые диагностики.
---
## Выход
### Находки
```
[🔴/🟠/🟡] <краткая суть>
Где: <путь:строка>
Правило: #stdNNN п.X | антипаттерн «<название>» | #bslls:<Код>
Проблема: <что именно не так здесь>
Как исправить: <конкретно; для 🔴 — со ссылкой на пример из справочника>
```
Ключ локации `<путь>::<Метод>:<строка>` обязателен — по нему оркестратор дедуплицирует
находки с архитектурным контуром (правила — в `shared/routing-contract.md`).
### Записи следа
Минимум одна на каждый слой — выполненный или пропущенный:
```
[qg applied: layer=code, scope=query-in-loop, ids=[std436,bslls:QueryInLoop], verdict=clean]
[qg applied: layer=code, scope=attribute-access, ids=[qg:BSL-REF-DOT-ACCESS,std437], verdict=violation:qg:BSL-REF-DOT-ACCESS]
[qg skipped: layer=code, scope=static-analysis, planned=[bslls:*], reason=analyzer_unavailable]
```
Вторая строка — из тех, что печатает инструмент: `attribute-access` стал инструментальным, и
написанная руками, она валидатор больше не проходит.
Формат — `../quality-gate/references/evidence-format.md`.
Два измерения контур закрыть не может и обязан об этом сказать. **Компилируемость тел
модулей** проверяет только платформа: без запуска проверки конфигурации нужна запись
`[qg not_verified: dimension=compilation, reason=no_platform]`, иначе полностью чистый вердикт
валидатор отклонит. **Выполнимость запроса** — то же самое при сработавшем архетипе «Запрос»:
```
[qg applied: layer=code, scope=query-execution, ids=[qg:QRY-EXECUTED], verdict=clean]
[qg not_verified: dimension=query-execution, reason=no_platform]
```
Лексическая проверка текста (пункт 3 Слоя 1б) её не заменяет — «Поле не найдено» и
несовместимость типов в `ОБЪЕДИНИТЬ` всплывают только при выполнении. Почему оба измерения
устроены так — `../quality-gate/references/evidence-format.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!