Baseline¶
Baseline версии 15 хранит принятые группы как потолки сообщаемых величин, включая определение исключений, при котором долг был принят.
Создание и использование baseline¶
Добавь проверенный файл в репозиторий. Сравнимое превышение становится Error; несравнимая группа сохраняет обычную серьёзность.
Миграция находок слоёв после изменения свидетельств объявлений¶
architecture.layer-violation теперь принадлежит точному объявлению источника,
включая файл и ordinal объявления. Принадлежащие проекту цели продолжают различать
occurrence: порядок целей, повторные объявления и количество сохраняются.
Параметры/return сохраняют type_hint, promoted property получает property_type,
объявления констант — constant_type. Прежние записи с union_type и
intersection_type становятся inert: эти формы синтаксиса теперь находятся в
объекте shape графа.
То же относится к ссылкам внутри аргументов атрибутов (Repo::class,
new Foo() и подобные): вид их ребра теперь attribute_argument, поэтому запись
baseline для такого ребра меняет идентичность edge.type и выглядит как одна
устаревшая и одна новая запись. Если ссылка разрешена, добавь attribute_argument
в relations: политики.
Проверь находки до изменения принятого долга. Сохрани имеющийся baseline, добавь новые source identities и удали только явно выбранные прежние identities:
vendor/bin/qmx check src/ --baseline=baseline.json
vendor/bin/qmx baseline:cleanup baseline.json src/
vendor/bin/qmx baseline:cleanup baseline.json src/ --disable-rule=architecture.layer-violation
vendor/bin/qmx baseline:update baseline.json src/ --only-rule=architecture.layer-violation --accept-new=architecture.layer-violation
vendor/bin/qmx baseline:cleanup baseline.json src/ --remove=SELECTOR_FROM_REPORT
Первые две команды cleanup — отчёты без записи. Обычный отчёт может назвать
записи с удалёнными видами рёбер inert; прежняя valid запись с target subject может
остаться outside coverage, когда исключения не дают доказать её отсутствие.
Второй отчёт намеренно не измеряет нарушения слоёв и публикует прежние селекторы
как not measured или malformed. Скопируй селекторы из этого отчёта, затем вызови
последнюю команду отдельно для каждой выбранной прежней записи слоя. Не используй
хеши другого проекта и не выводи селектор из occurrence id. --accept-new только
добавляет ранее отсутствовавшие группы, не ослабляя и не ужесточая имеющиеся
потолки. Сторонние tightened/suppress записи, записанная область и исключения
сохраняются. Ни --force, ни новый baseline не нужны.
В проверочном проекте миграции четыре прежние записи слоя и пять текущих source находок: аннотация на цели больше не скрывает входящее нарушение. Перенеси намеренное исключение исходящих рёбер на объявление источника. Неиспользованность target-аннотации сообщается только при достаточном покрытии директив; baseline с исключениями этого ответа не гарантирует. См. подавление нарушений слоя.
Что измеряется¶
Захват и сравнение используют одинаковые находки после правил, inline-подавлений и настроенных подавлений путей/пространств имён, до Git-проекции отчёта. --no-suppression-annotations возвращает находки только в отчёт после этой границы. Аудит и configuration-error каналы не захватываются. Magnitude хранит полный вектор; occurrence — число. Идентичность включает типизированный субъект, канал, необязательные occurrence и ребро зависимости.
Configuration errors включают пять диагностик layer-policy (
architecture.coverage-gap, architecture.unreachable-layer,
architecture.potential-shadow, architecture.empty-template,
architecture.pending-layer-matched) и три диагностики inline-директив (
annotation.unresolved-directive, annotation.unsupported-threshold,
annotation.invalid-threshold).
Сравнение требует полного анализа и совместимых свидетельств для всей группы. Baseline владеет RunCoverage: текущие/записанные пути и исключения, AnalysisCoverage, метаданные и область субъекта. Точный файл можно сравнить без полного списка Composer; пространства имён и зависимые от запуска каналы требуют более широкой области. Неизвестные метаданные не означают отсутствие. Равные пути/исключения могут доказать равенство без снимка; изменения требуют свидетельств о дельте. Project требует Whole.
Отсутствующему точному файлу или объявлению нужен положительно существующий
записанный корень, содержащий его путь, прежде чем отсутствие станет stale.
Алиас каталога подходит, если его каноническая цель содержит субъект. Исчезнувший
записанный корень и неизвестные метаданные этого не доказывают. Удалённый точный
субъект зависимого от запуска производителя может стать stale; присутствующему
нужна более широкая область. Без текущего участника, доказывающего принадлежность
PSR-4, отсутствие неймспейса требует Whole. Без записи baseline команда
baseline:explain требует обнаруженный исходный корень, выбранный содержащий
корень и положительно существующий каталог.
Полное сравнимое отсутствие означает stale. Невыбранный производитель означает unmeasured, несравнимое отсутствие — outside coverage. Присутствующая несравнимая группа получает not-compared, сохраняя серьёзность, принятую границу и причину. Неполный анализ не доказывает принятие, превышение или stale. Одна неконечная величина делает недоступным весь magnitude-вектор: конечный фрагмент не сравнивается и не захватывается. Occurrence считает всех членов. Сравнимое превышение поднимает всю группу до Error. Suppress отменяет количественное сравнение после применимости identity.
Lifecycle-команды¶
Четыре анализирующие команды принимают конфигурацию, пресеты, выбор/опции правил, include-generated/include-autoload-dev, кэш, workers и memory. CLI-подавления не принимаются. Неполный анализ возвращает 4 до записи даже с --force; байты сохраняются. Check, update, cleanup, explain и rename-channels один раз читают имеющийся документ до анализа/переноса. Грамматика проверяется рано, семантика каналов — после настройки по тому же неизменяемому снимку байтов. Ошибки хранения и блокировки, изменение baseline во время записи и нечитаемый baseline относятся к отказу среды с кодом 3; посторонние дефекты дают код 5. Отказ до анализа не публикует профиль.
Generate, update и cleanup с записью подготавливают временный сосед до анализа. Родитель должен разрешать создание и замену даже при существующем конечном файле. Полные байты публикуются атомарно после проверок идентичности и хеша содержимого; update/cleanup без изменений сохраняют конечные байты и inode. SIGINT/SIGTERM до публикации удаляют собственный сосед и дают 128 + номер сигнала, когда доступны pcntl и монопольное владение обработчиками. Иначе обычная атомарная публикация выполняется без замены чужих обработчиков, а при прерывании временный сосед может остаться. Замена обработчиков во время защищённой операции не поддерживается. Гарантия также не охватывает SIGKILL, ошибку удаления и уже опубликованные цели.
Generate¶
bin/qmx baseline:generate baseline.json src/
bin/qmx baseline:generate baseline.json src/ --mode=suppress --force
По умолчанию ratchet. Suppress принимает применимую identity независимо от роста. Force заменяет старое принятие, не мигрирует его. Родитель назначения должен существовать и разрешать атомарную публикацию соседа. Режим файла, блокировка и CAS по хешу содержимого сохраняются.
Замена старого baseline¶
Текущая версия v15, v14 тоже загружается (её записи на замыкания выведены из обращения, см. Переход с версии 14). Только для v13: сохрани entries, scope и generated, замени version на 14 и явно добавь исходное определение исключений, затем пройди переход с версии 14; дальше номер вручную не меняй. Определение исключений выглядит так:
Patterns используют явные exact/subtree/regex; generated — included/excluded.
Не выводи старое принятие из новой конфигурации. Неизвестные ключи envelope/entry/edge/
exclusion отклоняются с указанием позиции; непригодные значения известных полей
остаются inert. Старые форматы identity требуют проверенного преобразования;
новая генерация принимает новый долг, а не конвертирует старый.
Непригодная группа subject, записанная JSON-объектом, сохраняет форму объекта при
обновлении других subject. Добавление записи к тому же subject отклоняется до
замены файла. Просмотри кандидатов cleanup и удали эту группу через
baseline:cleanup --remove=<selector> перед принятием новой записи;
по умолчанию cleanup только перечисляет кандидатов.
Переход с версии 14¶
Версия 14 называла замыкание по его номеру среди всех замыканий файла; версия 15
называет его по объемлющему объявлению (App\A::rows::{closure#1}). Файл версии 14
загружается, но каждая запись под ключом замыкания inert как
retired closure identity и ничего не принимает. Каждая команда, которая
записывает из него версию 15 (baseline:update, baseline:cleanup --remove),
отказывает (exit 3, ничего не записано), пока такая запись осталась.
baseline:rename-channels записывает прочитанную версию, поэтому результат
остаётся версией 14, а записи — выведенными из обращения.
Не переводи файл правкой "version": 14 на 15. Номер — единственный признак
старых ключей замыканий: под 15 они загружаются как действующие и молча принимают
то замыкание, которое сейчас носит их номер. Единственная процедура:
bin/qmx baseline:cleanup baseline.json src/
bin/qmx baseline:cleanup baseline.json src/ --remove=SELECTOR_1 --remove=SELECTOR_2
bin/qmx baseline:update baseline.json src/ --accept-new=code-smell.debug-code
- Перечисли выведенные записи (первая команда только читает).
- Удали их все одним вызовом: он запишет версию 15 и сохранит остальные записи. Две записи одной продублированной identity замыкания имеют общий selector, который удаляет обе.
- Замыкания теперь видны как новые находки. Исправь их или прими через
--accept-new=<channel>, который принимает все новые identity этого канала: просмотри diff.
Не используй baseline:generate --force: он заново фиксирует посторонние потолки.
Ужесточение после исправлений¶
bin/qmx baseline:update baseline.json src/
bin/qmx baseline:update baseline.json src/ --accept-new=architecture.layer-violation
bin/qmx baseline:update baseline.json src/ --record-exclusions
Обычный update только ужесточает имеющиеся группы, сохраняя scope, exclusions, inert payload и modes. Равное принятие — unchanged; отсутствие изменений не вызывает writer, не меняет generated/байты и не создаёт блокировку. Отсутствующие/несравнимые группы сохраняются, а не превращаются в ноль. --force обходит обычный scope guard, но не доказывает сравнимость и не разрешает неполный анализ.
Повторяемый --accept-new=channel добавляет только новые полные сравнимые измеренные identity явно названных выбранных каналов, не ужесточая старые границы. Допуск точных каналов происходит после настройки до анализа. Необъявленные каналы, wildcard, суффикс уровня, configuration-error и baseline.unused-entry отклоняются с кодом 3.
--record-exclusions требует точно записанные пути даже с --force. Записывает полное новое определение, перезахватывая только группы, которым мешала исключительно дельта исключений, с сохранением modes. Другие записи проходят обычное ужесточение. Неизвестная дельта, изменение generated-policy без достаточных доказательств, неполный анализ или недоступная необходимая группа запрещают всю запись. Опции несовместимы.
Отсутствующая запись file: или точная declaration: удаляется с причиной
exclusions-removed-population,
только если полный список и прогон точно по записанным путям доказывают, что её
собственный существующий PHP-файл исключён новым селектором, а generated-policy
не менялась. Cleanup предлагает тот же selector. Записи связей без исходного
пути по-прежнему отказывают при недоступной необходимой группе. Update называет
все исходы до отказа всей записи; успешные записи отдельно не публикуются.
--accept-new проходит обычный scope guard; --force обходит только этот guard.
Повторные имена JSON-полей отклоняются только среди envelope и subject keys
полностью распознанной канонической раскладки. Entry objects и неканонический
fallback сохраняют поведение json_decode: последнее одноимённое поле побеждает.
Обнаружение повторов там не гарантируется, включая канонический префикс,
за которым раскладка перестала распознаваться.
Нормализованный принятый payload сохраняется для произвольного пользовательского JSON. Точные байты неизменённых entry гарантируются только для канонического writer input; порядок полей и числовое написание пользовательского JSON могут нормализоваться.
Проверка и явное удаление stale-записей¶
bin/qmx baseline:cleanup baseline.json src/
bin/qmx baseline:cleanup baseline.json src/ --remove=<selector>
По умолчанию только список, без записи. Удаляй проверенные selectors, повторяя --remove. Уменьшившаяся срабатывающая группа не stale. Unmeasured/outside не доказывает исправление. Старые необъявленные уровни остаются inert, а не группами с нулём. Если selector называет только inert-претендентов одной повторной идентичности, удаляются все эти претенденты. Другие коллизии selector по-прежнему отклоняются как неоднозначные.
Перенос baseline на переименованные каналы¶
bin/qmx baseline:rename-channels baseline.json channels.tsv
bin/qmx baseline:rename-channels baseline.json channels.tsv --format=json
TSV-карта содержит старые/новые каналы. Команда не анализирует код, заменяет только названные channel, сохраняет entries/scope/exclusions/generated и отклоняет созданные коллизии identity. Действует общая закрытая грамматика: неизвестные поля не переносятся. Selector меняется вместе с каналом identity.
baseline:update и baseline:cleanup без --force отказывают с кодом 3 и причиной в stderr, когда текущий прогон не покрывает охват, записанный в baseline. Прогон, который покрывает этот охват, допустим.
Объяснение границы¶
Пустой --channel= отклоняется с кодом 3.
Отдельные строки baseline и now показывают независимые принятие и текущие свидетельства, даже без baseline или с inert. Состояния: reported, nothing reported, not measured, outside coverage, not compared, level not reported. Необъявленный уровень перечисляет допустимые. Неизвестная форма остаётся неизвестной; неконечная magnitude-группа показывает полный/неизмеренный count без выдуманного частичного вектора. Границы, suppress и inert причина видны независимо.
Намеренно пустой исключённый набор¶
Полный запуск без анализируемых файлов с намеренными authored/generated exclusions может создать пустой baseline. Неполный ввод приоритетен (4). Неизвестные метаданные или исключение не доказывают исчезновение принятого субъекта.
Stale, inert и resolved-записи¶
--show-resolved считает исчезнувшие полные сравнимые identity, а не исправленных членов сохранившейся группы. Stale/inert публикуются как предупреждение аудита. Невыбранный аудит и несравнимые записи дают только счётчики stderr без списков путей. Полный ceiling предшествует Git/hook: проектные предупреждения остаются рядом с выбранными файлами. Узкие Run-каналы могут стать not-compared вместо принятия или превышения.
Подавление в исходниках¶
Используй inline-подавление для намеренного исключения, а не молча принимай его в baseline. Теги работают в PHPDoc, строчных и блочных комментариях; помещай их на отдельной строке перед целью.
| Тег | Область | Пример |
|---|---|---|
@qmx-ignore <channel> [-- reason] |
Символ | @qmx-ignore complexity.ccn:callable -- Legacy state machine |
@qmx-ignore * [-- reason] |
Все правила символа | @qmx-ignore * -- Generated mapper |
@qmx-ignore-next-line <channel> [-- reason] |
Следующая строка | @qmx-ignore-next-line code-smell.exit -- CLI entry point |
@qmx-ignore-file [channel] [-- reason] |
Весь файл | @qmx-ignore-file или @qmx-ignore-file -- Generated code |
Грамматика строки комментария¶
Тег стоит в начале физической строки комментария после пробелов и
оформления (//, /*, *, #). Однострочный /** @qmx-ignore ... */
допустим: PHP-код может предшествовать комментарию, но текст внутри комментария
не может предшествовать тегу. Точный тег посреди текста получает отказ
annotation.unresolved-directive; отдельные теги пиши на отдельных строках.
Аргументы остаются на строке тега, а закрывающее */ не считается аргументом.
Написания тегов @qmx-ignore, @qmx-ignore-next-line,
@qmx-ignore-file и @qmx-threshold точны. Близкие написания в начале строки, в том
числе другой регистр, подчёркивания, пробелы или пропущенный разделитель/@,
считаются опечатками. Обычный текст вроде qmx ignores не является директивой.
Как цитировать примеры¶
На одной строке окружай пример парными последовательностями обратных кавычек
одинаковой длины. Между открывающей последовательностью и тегом допустимы
только пробелы, оформление комментария и обратные кавычки. Одиночная кавычка,
неравные длины или текст перед тегом внутри пары не экранируют его.
Например, Write `@qmx-ignore complexity.ccn` описывает тег,
а `example @qmx-ignore complexity.ccn` получает отказ.
Для многострочного примера открой блок после пробелов/оформления тремя или более обратными кавычками либо тильдами. После открытия допустимо имя языка, но после открытия обратными кавычками не должно быть ещё обратной кавычки. Закрытие использует тот же символ и не меньшую длину; после него допустимы только пробелы и необязательное закрытие комментария. Более короткое или смешанное закрытие блок не закрывает. Закрытый блок цитирует содержимое; незакрытый блок даёт отказ для строк с директивами внутри и указывает строку открытия.
Привязка к декларации и границы члена¶
Подавление декларации привязывается к измеряемой декларации, на которой стоит.
Docblock в любой части заголовка декларации, в том числе между группами
атрибутов или между function и именем, принадлежит ей.
Извлечение читает исходные байты, не изменяя кешированный AST.
Замыкание или стрелочная функция привязывается, когда оно — прямое значение
аргумента, элемента массива, return, выражения или цепочки присваиваний
(= либо ??=). Имя аргумента или ключ массива перед значением допустимы.
Вызов, тернарное выражение, массив-обёртка или иное выражение, лишь содержащее
замыкание, к нему не привязывается: перенеси комментарий непосредственно перед
function или fn. Инструкция без измеряемой декларации получает отказ;
для строки используй физическую форму next-line.
Место @qmx-ignore |
Граница подавления |
|---|---|
| Класс, интерфейс, трейт или enum | Вся декларация и её измеряемые callable-члены |
| Метод | Весь метод; находки класса на строках метода |
| Функция, замыкание, стрелочная функция или property hook | Весь callable |
| Свойство с hooks | Все hooks; находки класса на строках свойства |
| Свойство без hooks, константа класса или enum case | Находки класса на строках члена |
| Параметр | Находки callable на строках параметра |
| Продвигаемый параметр | Строки параметра для находок callable и класса; все property hooks, если есть |
Аннотация члена не подавляет находку всего класса на строке класса или находку
соседнего члена. Границы — включительные диапазоны строк, поэтому параметры
на одной строке не различаются по колонке.
Явный :level должен быть объявлен каналом и достижим здесь: :class на
методе или продвигаемом параметре допустим; :callable на константе или
свойстве без hooks получает отказ. Селектор без уровня покрывает достижимые
уровни без отдельной дополнительной проверки уровня.
@qmx-threshold не получает границы содержащего члена: class-like
декларация меняет пороги себя и измеряемых callables; метод/функция/замыкание/
стрелочная функция/hook — себя; свойство с hooks — свои hooks.
Обычное свойство, константа, enum case или параметр не привязывает threshold.
Физические места и общие подавления¶
Каждый прочитанный тег — одно авторское место, даже если он создаёт несколько привязок. Подавления и диагностики threshold сохраняют байтовую позицию тега: одинаковые теги в двух комментариях одной строки остаются разными местами. У next-line публикуется строка тега; цель — строка после конца комментария, включая многострочные комментарии. Threshold overrides позиции не несут, поэтому overrides одного правила на одной строке пока сливаются.
@qmx-ignore * и голый @qmx-ignore-file получают effective, когда подавили
произведённую находку, и inert, когда ничего не подавили. Они не могут заглушить
annotation.unused-directive или duplication.clone; ошибки конфигурации
остаются вне подавления аннотациями. Явный селектор запрещённого канала получает
отказ; достижимость декларации/уровня проверяется раньше запрета.
Разделитель причины¶
Аргумент канала и причина — оба голые слова, поэтому -- — это способ их
различить. Он обязателен для @qmx-ignore-file, когда канал опущен, а
сразу за тегом идёт причина: @qmx-ignore-file Generated code, do not
analyse читает Generated как канал, который ничему не адресуется, и
падает с annotation.unresolved-directive:
Suppression "Generated" addresses no channel. No declared name is close to it. Prose belongs after "--".
Пишите так: @qmx-ignore-file -- Generated code, do not analyse. У
@qmx-ignore и @qmx-ignore-next-line канал не опционален — он всегда
первое слово, — поэтому -- перед причиной там необязателен; собственное
соглашение проекта — писать его всё равно, чтобы все три тега читались
одинаково.
Каналы, а не имена правил¶
@qmx-ignore, @qmx-ignore-next-line и @qmx-ignore-file адресуют канал — точный violationCode, под которым сообщается нарушение, — а не производящее правило. Селектор канала — это либо:
- точное имя канала (
complexity.wmc,code-smell.eval), опционально суженное через:<уровень>(complexity.ccn:callable), когда канал сообщает на нескольких уровнях, либо X.*строго для потомковX— самXв это не входит, поэтому для обоих смыслов нужны две директивы.
Голый префикс без звёздочки (@qmx-ignore complexity) — это ошибка, а не догадка о намерении; X.*, не совпавший ни с чем, тоже ошибка:
Один producer может публиковать несколько каналов. Сам канал также может сообщать находки на нескольких уровнях дерева символов — например, класс и namespace. Голый канал обращается ко всем его уровням сразу; следующие каналы часто требуют ограничения уровнем:
| Канал | Уровни |
|---|---|
complexity.ccn |
callable, class |
complexity.cognitive |
callable, class |
complexity.npath |
callable, class |
coupling.cbo |
class, namespace |
coupling.instability |
class, namespace |
Подавляй все уровни голым именем канала или один уровень через :уровень, например @qmx-ignore complexity.ccn:callable.
Каналом может быть и вычисляемая метрика, например @qmx-ignore health.cohesion — это допустимо, пока computed_metrics: всё ещё определяет эту метрику. Удаление метрики превращает аннотацию в ошибку: висячая ссылка — та же ошибка, что и опечатка.
Пять каналов здесь никогда нельзя подавить
architecture.coverage-gap, architecture.unreachable-layer, architecture.pending-layer-matched, architecture.potential-shadow и architecture.empty-template — это конфигурационные ошибки, а не долг: @qmx-ignore не может их подавить, а baseline никогда не может их принять. Используй блок exclude: в конфигурации архитектуры или coverage-gap: ignore специально для диагностики покрытия. architecture.layer-violation это не касается — @qmx-ignore architecture.layer-violation и записи baseline для него по-прежнему работают.
Когда директива неверна¶
Директива, называющая что-то недопустимое, или директива, которая больше ничего не подавляет, не игнорируется молча — она сама становится нарушением встроенного правила annotation.directive, сообщаемым на файле, где находится директива. Полный справочник — Правила аннотаций. Три из четырёх её каналов — конфигурационные ошибки, которые безусловно завершают прогон независимо от --fail-on и никогда не могут быть приняты в baseline или подавлены:
| Канал | Когда срабатывает |
|---|---|
annotation.unresolved-directive |
директива называет несуществующий канал (опечатка, имя правила там, где нужен канал, X.*, не совпавший ни с чем, или удалённая вычисляемая метрика) — либо она вообще не стала директивой: тег @qmx-, который инструмент не читает, или декларационная форма, написанная там, где ничего не измеряется |
annotation.unsupported-threshold |
@qmx-threshold нацелен на правило, не объявляющее поддержку override порога |
annotation.invalid-threshold |
сам payload @qmx-threshold некорректен |
annotation.unused-directive |
директива корректна, но ничего из адресованного ею не сработало за этот прогон — обычный долг по уборке |
Только annotation.unused-directive ведёт себя как обычное нарушение: по умолчанию это Warning, серьёзность настраивается через опцию правила unused-directive-severity (явное info сохраняет прежнюю серьёзность), его можно принять в baseline, убрать корневым suppress_paths или сузить git-скоупом как любой другой канал. suppress_namespaces до него не достаёт — субъект находки это файл, в котором написана аннотация, и неймспейса у него нет, — и собственные исключения правила тоже: они работают раньше, чем этот канал собирается. Как и duplication.clone, его нельзя погасить @qmx-ignore: директива, адресующая его, отвергается как annotation.unresolved-directive, — поэтому принять его на месте можно записью в baseline. @qmx-threshold никогда в него не засчитывается.
Тег с опечаткой, неверным размещением на строке или без допустимой привязки получает отказ; подавление на свойстве теперь имеет границы члена. См. раздел «Формы, которые директивой так и не становятся» на странице Правила аннотаций.
Просмотр скрытого аннотациями¶
--show-suppressed показывает подавленные нарушения. --no-suppression-annotations возвращает нарушения, скрытые @qmx-ignore, только в отчёт: они остаются вне измеряемого baseline множества, сохраняют собственную серьёзность и не могут быть повышены записью baseline.
Переопределение порогов для символа с @qmx-threshold¶
Используй @qmx-threshold, когда символу нужна другая граница, но он должен оставаться проверяемым:
/**
* @qmx-threshold complexity.ccn warning=20 error=40 -- Legacy state machine
*/
final class ComplexStateMachine
{
}
@qmx-threshold <rule> <number> [-- <reason>]
@qmx-threshold <rule> warning=<number> [error=<number>] [-- <reason>]
Duplication — отдельное исключение: @qmx-threshold duplication.clone отклоняется с annotation.unsupported-threshold, поскольку правило не поддерживает локальные переопределения.
@qmx-threshold адресует правило по точному имени — никогда канал и никогда уровень. Порог принадлежит единственному объекту опций правила, а не отдельному уровню, поэтому @qmx-threshold complexity.ccn:callable — ошибка, даже несмотря на то, что complexity.ccn сообщает на двух уровнях; используй имя правила complexity.ccn, а для настройки только одного уровня — --rule-opt:
@qmx-threshold "complexity.ccn:callable" addresses a rule at a level, and a threshold addresses the
producing rule by its own name: it does not distinguish levels (ADR 0024). Retune the whole rule
"complexity.ccn", or set the level alone with --rule-opt complexity.ccn:callable.<option>=<value>.
Это зеркальное отражение @qmx-ignore, который всегда адресует канал — асимметрия намеренная. @qmx-threshold на отключённом правиле допустим и работает молча: включённость — это фильтр исполнения, а не факт существования имени правила.
Числа неотрицательные. Явная форма принимает только warning и error; после -- или длинного тире пишется непустая причина. Override класса действует внутри класса, включая методы, override метода — только на этот метод, а при пересечении побеждает наименьшая исходная область. Предпочитай это @qmx-ignore, когда полезная граница всё ещё существует.
Записи с байтовыми именами¶
Компоненты канонического subject кодируют буквальный % как %25, невалидные
байты как %XX, а #, зарезервированный в имени файла декларации, как %23.
Идентичности остаются различными по исходным байтам. После обновления прежние
записи для таких путей могут перестать совпадать: проверь и перенеси только их,
не перегенерируя baseline целиком.
Scope и exclusion selectors сохраняют исходные факты ввода. Baseline со scope или селектором вне UTF-8 отказывает с нативной причиной кодирования: переименование этих полей изменило бы сравнения. Анализируй содержащий каталог с UTF-8 именем, чтобы записать entry с байтовым именем. Байтовые JSON selectors не поддерживаются.