bsl-code-review — контур кода

SkillDev tools

BSL code review loop: static analyzer diagnostics, performance anti-patterns and platform mechanics, #stdNNN development standards, naming, API signature verification and common module existence checks. Works at the 'inside method body' level — issues fixable by replacing lines. Invoked by the orche

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the bsl-code-review — контур кода skill

What this skill tells your AI

The instructions your AI receives, as published by romandredan/1c-quality-gate in skills/bsl-code-review/SKILL.md and read by ahel’s 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а — статический анализ

Одна команда: она находит корень конфигурации, прогоняет только изменённые файлы, проверяет часового и формирует записи следа.

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б: он ловит другое и от анализатора не зависит.

Второй движок — сверка со справочником платформы

node "$QG/tools/platform-context-run.mjs" --changed <файл> [--changed <файл> ...]

Ловит то, чего анализатор не видит вовсе: несуществующий член платформенного типа, значение системного перечисления, конструктор, свойство объекта. Всё это компилируется и падает при выполнении. Сервер справки движок заводит сам: ищет поднятый, а не найдя — ставит закреплённый релиз и поднимает свой по установленной платформе. Где платформы на машине нет, пишет skipped с причиной и возвращает код 1 — это законный исход.

Два правила: info «низкая уверенность» не отбрасывать (класс смешанный) и часовой not_found — «чисто» запрещено. Остальное — references/platform-api.md.

Слой 1б — то, чего анализатор не видит

1. Антипаттерны производительности и механики платформы

Источник: references/bsl-anti-patterns.md — прогоняется всегда, при любой глубине.

АнтипаттернЧто искатьВажность
Запрос в циклеНовый Запрос внутри Для Каждого🔴
Чтение реквизита через точку.Реквизит у ссылочного типа — грузит объект целиком🔴
Подзапрос в списке полейвложенный ВЫБРАТЬ в секции выборки (N+1)🔴
Коррелированный подзапрос в условиивложенный ВЫБРАТЬ в ГДЕ, ссылающийся на внешнее поле🔴
Фильтр виртуальной таблицы в ГДЕусловие на результате ВТ вместо её параметров🟠
Временная таблица без индексаПОМЕСТИТЬ без ИНДЕКСИРОВАТЬ ПО, далее соединение по этому полю🟠
Отсутствие ограничения выборкибольшой запрос без ПЕРВЫЕ N🟠
Множественные серверные вызовыпоследовательные вызовы сервера с клиента🟠
Контекстный вызов без нужды&НаСервере там, где хватает &НаСервереБезКонтекста🟠
Транзакция внутри ПопыткиНачатьТранзакцию() внутри Попытка, а не наоборот🟠
Транзакция внутри неявной транзакцииНачатьТранзакцию() в ОбработкаПроведения, ПередЗаписью, ПриЗаписи🟠
Сообщить() как уведомлениесообщение без привязки к объекту и вне журнала регистрации🟠
Отсутствие кешированияповторные дорогие вызовы с теми же параметрами🟡
Поиск перебором во вложенных циклахсопоставление наборов циклом вместо Соответствие🟡

2. Антипаттерны кода, порождаемого моделью

Источник: references/ai-antipatterns.md — прогоняется всегда, наравне с предыдущим.

Ошибки, характерные для кода языковой модели: перепроверка контракта собственной функции, форк парсера на каждый вариант ответа, отчёт о непрогнанной проверке. Типовые своды их не покрывают — человек таких ошибок обычно не делает.

3. Проверки по тексту кода

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
qg:BSL-FORM-ATTR-SHADOW🔴имя реквизита формы у переменнойreferences/bsl-anti-patterns.md п. 8д
qg:BSL-DISPATCH-NO-FALLBACK🟠перебор значений перечисления или типов по трём и более веткам без Иначе: непредусмотренное значение проходит цепочку молчаreferences/bsl-anti-patterns.md п. 8е
qg:BSL-DB-READ-IN-LOOP🟠чтение базы, достижимое из тела цикла через вызов метода: то же N+1, что в п. 1, только распределённое по методам (#std436). Прямую форму ловит анализаторreferences/bsl-anti-patterns.md п. 1а

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-файлов. Он дешёвый, работает по той же процедуре и возвращает вердикт, список нарушений с локациями и раздел «Не проверено». Вызов один на весь список: каждый лишний инстанс поднимает свою сессию индекса кода, а справочник платформы на stdio-транспорте вдобавок не переносит параллельных обращений.

Если прогнан второй движок слоя 1а, платформенная часть уже закрыта: субагенту остаются общие модули, метаданные и контекст доступности.

Субагента в среде может не быть — тогда прогоняй 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 либо затронуты проведение, деньги, права, необратимые операции. Ценность даёт противоположность входов, а не второе мнение — почему, разбирает references/cold-reader.md.

Передавать: только сравнение версий и содержимое изменённых файлов. Не передавать: формулировку задачи, свои выводы, названия найденных проблем — узнавший намерение читатель перестаёт быть холодным.

Три вопроса, на которые он отвечает:

  1. Что этот код делает как написан, а не как задуман?
  2. На каких входных данных он ломается или ведёт себя неожиданно?
  3. Какое ожидаемое поведение из него не следует?

Модель — не дешёвая: выносится суждение о логике, уровень не ниже основной модели сессии. Расхождение его выводов с advisor() — сигнал, а не шум: код допускает два прочтения.

Слой 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.

Signals

GitHub stars
25
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
bsl-code-review
Source
github.com/romandredan/1c-quality-gate