Перейти к содержанию

Опции CLI

Qualimetrix предоставляет команду check для анализа кода и несколько вспомогательных команд для работы с baseline, git-хуками и визуализацией графа зависимостей.

Команда check

bin/qmx check [опции] [--] [<пути>...]

Аргумент paths

Укажите одну или несколько директорий или файлов для анализа:

# Анализ конкретных директорий
bin/qmx check src/ lib/

# Анализ одного файла
bin/qmx check src/Service/UserService.php

Отсутствующий итоговый путь или явно названный существующий обычный файл с расширением, отличным от .php, отклоняется с кодом 3 до discovery. Это действует для путей из CLI, YAML и пресетов в check, directives, graph:export, debug:layer-assignment и четырёх измеряющих командах baseline. Каталоги обходятся как обычно; дерево без PHP остаётся отдельным отказом анализа.

Путь, который вы называете и который сам является каталогом vendor, node_modules или .git (bin/qmx check lib/vendor), останавливает прогон ошибкой конфигурации: Qualimetrix никогда не заходит в такой каталог, и прогон не проанализировал бы ничего. Назовите файл или каталог внутри него (bin/qmx check vendor/acme/); каталог vendor внутри названного пути по-прежнему пропускается.

Авторские exclude: и --exclude применяются к названным файлам и каталогам из CLI, YAML и пресетов. exact: убирает только названную запись, subtree: — её и потомков. Совпавший написанный корень считается исключённым, а не ошибкой ввода. Если analyzed=0, failed=0 и excluded + generatedExcluded > 0, результат намеренно пуст: check и directives возвращают 0, graph:export пишет пустой граф, а baseline:generate — пустой baseline. Объяснение остаётся на stderr и в поддерживающих его отчётах. Любая неполнота имеет приоритет с кодом 4: диагностический отчёт сохраняется, baseline и авторитетный граф не записываются. Действительно пустое дерево без найденных или исключённых записей сохраняет прежние исходы каждой команды.

. и канонически эквивалентные формы корня допустимы. Каталог или directory alias должен канонически указывать внутрь захваченного корня; внешнее написание alias на внутренний каталог допустимо, обратное направление отклоняется с кодом 3. Для файла проверяется канонический родитель, а последнее имя сохраняется буквально, включая названную ссылку на внешний файл. --working-dir выбирает корень вызова; публикация пути не использует outside-root fallback.

Если пути не указаны, Qualimetrix автоматически определит их по всем путям, которые объявляет секция autoload вашего composer.json, — корням psr-4 и psr-0, записям classmap (шаблон * раскрывается в подходящие каталоги) и записям files. По этим же путям Qualimetrix судит, охватил ли прогон весь проект, итоговый охват также учитывает отсутствующие PHP-файлы, авторские и generated-исключения и известность состава кода. Запись, которая сама является каталогом vendor, node_modules или .git или лежит внутри него (Qualimetrix туда никогда не заходит), не входит ни туда, ни туда и называется в предупреждении: сторонний код не анализируется как код вашего проекта. Объявленный путь, которого нет на диске, останавливает прогон ошибкой конфигурации. autoload-dev не включается: тестовый код анализируется, только когда его путь назван явно (bin/qmx check src/ tests/ или paths: в qmx.yaml), или когда вы считаете его частью проекта через --include-autoload-dev.


Опции файлов

--config, -c

Путь к YAML-файлу конфигурации:

bin/qmx check src/ --config=qmx.yaml

Пустое значение — не то же, что опция не указана. --config= — обычно это --config=$QMX_CONFIG с незаданной переменной — отклоняется с кодом 3, а не откатывается на qmx.yaml из рабочего каталога. То же для --baseline=, --output=, --report= и --preset= (включая пустое имя в списке вроде --preset=strict,): чтобы получить значение по умолчанию, опцию нужно просто не указывать.

Предупреждения о конфигурации, которую команда приняла, — например, only_rules: [], снимающий фильтр пресета, — каждая команда, читающая конфигурацию, пишет в stderr строками Warning:, а check --format=json дополнительно несёт их в configurationDiagnostics. См. Предупреждения о конфигурации.

--exclude

Исключить директории из анализа явным селектором пути. Можно указывать несколько раз:

bin/qmx check src/ --exclude=subtree:src/Generated --exclude=exact:src/Legacy

Привязка проверяется каналом discovery.unmatched-exclude. Полнота PHP-путей и известность состава кода допускают проверку ещё не привязанных селекторов; авторские и generated-исключения сами по себе её не закрывают. Привязанный селектор остаётся Removed и на узком прогоне. Возможное скрытое поддерево своего источника даёт ограниченное предупреждение, другого источника — именованный пропуск с предложением повторить прогон без исключения. Исключённый написанный корень измеряется, а не отклоняется. См. аргумент paths.

--include-generated

По умолчанию Qualimetrix автоматически пропускает файлы, содержащие аннотацию @generated в первых 2 КБ. Этот флаг переопределяет это поведение и включает сгенерированные файлы в анализ:

bin/qmx check src/ --include-generated

Также можно задать в qmx.yaml:

include_generated: true

--include-autoload-dev

Считает код, объявленный в composer.json в секции autoload-dev, частью проекта. Обе половины прогона следуют этому вместе:

  • прогон без путей анализирует все пути, которые объявляет autoload-dev в любой форме автозагрузки, рядом с путями autoload;
  • когда Qualimetrix проверяет, охватил ли прогон весь проект, autoload-dev тоже входит в проверку — поэтому bin/qmx check src/ --include-autoload-dev предупреждает, что tests/ не проанализирован, а каналы, которые говорят только на прогоне по всему проекту, молчат.

Пути, названные вами явно, не расширяются. По умолчанию выключено:

bin/qmx check --include-autoload-dev

Можно задать и в qmx.yaml:

include_autoload_dev: true

--suppress-path

Подавить нарушения для файлов, выбранных через exact:, subtree: или regex:. Значение CLI делится по первому двоеточию; regex — фрагмент PCRE без разделителей, автоматически привязанный ко всему пути. Файлы по-прежнему анализируются, опцию можно повторять:

bin/qmx check src/ --suppress-path='subtree:src/Entity' --suppress-path='regex:src/DTO/.*\.php'

Объединяется с suppress_paths из qmx.yaml — оба источника суммируются.

Объявленные project-scoped каналы остаются видимыми

Циклы architecture.circular-dependency и project-scoped diagnostics не подавляются. Для architecture.layer-violation опция применяется к источнику нарушения; см. Подавление путей в отчёте.

--suppress-namespace

Подавить нарушения для классов, выбранных явным селектором неймспейса. subtree: следует границам неймспейса, а regex: задаёт полнообъектный фрагмент PCRE. Классы по-прежнему анализируются, опцию можно повторять:

bin/qmx check src/ --suppress-namespace='subtree:App\Entity' --suppress-namespace='regex:App\\DTO(?:\\[^\\]+)*'

Объединяется с suppress_namespaces из qmx.yaml — оба источника суммируются.

Объявленные project-scoped каналы остаются видимыми

Циклы architecture.circular-dependency и project-scoped diagnostics не подавляются. Для architecture.layer-violation опция применяется к источнику нарушения; см. Подавление неймспейсов.


Опции пресетов

--preset

Применить именованный пресет или пользовательский YAML-файл. Можно указывать несколько раз или через запятую:

# Встроенные пресеты
bin/qmx check src/ --preset=strict
bin/qmx check src/ --preset=legacy

# Комбинирование пресетов (объединяются слева направо)
bin/qmx check src/ --preset=strict,ci
bin/qmx check src/ --preset=strict --preset=ci

# Пользовательский файл пресета
bin/qmx check src/ --preset=./my-preset.yaml

Доступные встроенные пресеты: strict, legacy, ci.

Пресеты применяются после автоопределения composer.json, но до qmx.yaml, поэтому ваш файл конфигурации всегда имеет приоритет. Подробности смотрите в разделе Конфигурация > Пресеты.

Встроенный пресет можно также импортировать из файла конфигурации — imports: [strict] — тогда он применяется к каждому запуску, читающему файл, включая pre-commit-хук и GitHub Action, ни один из которых не передаёт --preset. Импортированный пресет стоит в полосе файла конфигурации, выше пресетов из --preset. См. Конфигурация > Встроенные пресеты.


Опции вывода

--format, -f

Выбор формата вывода. По умолчанию: summary.

bin/qmx check src/ --format=json
bin/qmx check src/ --format=sarif

Доступные форматы: summary, text, json, metrics, checkstyle, sarif, gitlab, github, health, html, suppressed.

Подробности о каждом формате смотрите в разделе Форматы вывода.

--output, -o

Записать отчёт в файл вместо stdout:

bin/qmx check src/ --format=html --output=report.html

Названный обычный файл подготавливается после проверки конфигурации, области анализа, селекторов и входного baseline, до анализа. Результат удерживается во временном соседнем файле; новое конечное имя отсутствует, прежние байты сохраняются до полной записи, сброса буферов и проверки идентичности перед атомарной публикацией. Замена сохраняет права и меняет конечный inode; другие жёсткие ссылки сохраняют прежние байты. Родительский каталог должен существовать и разрешать создание и замену, даже если конечный файл уже существует и доступен для записи. Перенеси цель или разреши запись и поиск в родительском каталоге до запуска qmx.

SIGINT/SIGTERM до публикации удаляют собственный временный файл прогона и дают 128 + номер сигнала, когда доступны pcntl и монопольное владение обработчиками. Иначе обычная атомарная публикация выполняется без замены чужих обработчиков, а при прерывании временный сосед может остаться. Замена обработчиков во время защищённой операции не поддерживается. Гарантия уборки также не охватывает SIGKILL, ошибку удаления и уже опубликованные цели. Профиль, уже опубликованный до позднего сбоя отчёта, не откатывается.

Символическая ссылка принимается, только если другой пользователь не может подложить эту запись каталога. Принятая ссылка сохраняется, запись меняет её разрешённую цель; это относится и к висячей ссылке в существующий каталог. Подменяемая ссылка отклоняется на обычном и thread-safe PHP. Возможность изменить другие части пути сообщается в stderr до анализа. Для гонок подмены компонентов, ACL, происхождения жёстких ссылок и нелокальных файловых систем сохраняются ограничения платформы.

Своя ссылка в каталоге 0775 принимается, если группа каталога доказанно является личной первичной группой эффективного пользователя: в ней нет других первичных или дополнительных участников. Проверка поддерживает полное перечисление отдельных NSS-источников files и systemd. Неизвестные источники, явный initgroups, ошибка перечисления или неподдерживаемая платформа сохраняют консервативный отказ.

/dev/stdout, /dev/stderr, /dev/fd/N, /proc/self/fd/N, /proc/thread-self/fd/N, php://stdout, php://stderr и php://fd/N обращаются к существующему потоку процесса; написания /proc требуют procfs. file:///absolute/path задаёт файловый путь. Остальные URI-схемы отклоняются. Именованный канал открывается после проверок ввода и требует читателя; /dev/null поддерживается.

Существование дескриптора проверяется до анализа. Linux fdinfo также позволяет рано отклонить дескриптор, открытый только для чтения. На macOS PHP не раскрывает его исходный флаг доступа, поэтому неизвестный режим оставляется до настоящей записи и её отказа среды. Запись в дескрипторы и потоки использует блокирующий режим.

Адресаты отчёта, профиля и лога проверяются вместе. Два адресата одного обычного inode или одного отсутствующего имени отклоняются до анализа, как и адресат, совпадающий с входным baseline. Адресат, совпадающий с файлом, который читает прогон, тоже отклоняется до анализа:

  • с файлом конфигурации — найденным qmx.yaml/qmx.yml (или qmx.dist.yaml/qmx.dist.yml) или файлом --config, каждым импортированным им файлом, каждым файлом пресета;
  • с composer.json рабочего каталога, объявляет он пути автозагрузки или нет;
  • с PHP-файлом, который выбирает прогон, — анализируемым или исключённым как сгенерированный.

Файлы сравниваются по идентичности, поэтому другое написание, символическая или жёсткая ссылка отклоняются так же. Новый файл среди анализируемых исходников, например --output=src/report.json, записывается. Тому же правилу следуют graph:export --output и файл baseline, который пишут baseline:generate, baseline:update и baseline:cleanup. Если отчёт check или graph:export идёт в stdout, а оболочка открыла stdout на таком файле (>>, 1<>), прогон тоже отклоняется раньше любого другого адресата, и отказ выводится только в stderr; при > оболочка опустошает файл ещё до запуска qmx. Отказ, возникший раньше, пока читаются опции и конфигурация, как обычно выводится в stdout в запрошенном формате. Выбор исходников стоит одного дополнительного обхода анализируемых путей без чтения файлов и выполняется, только когда адресат или перенаправленный stdout — существующий обычный файл.

Не проверяются: другие файлы Composer, которые читает прогон (composer.json выше рабочего каталога или рядом с анализируемым пакетом, vendor/composer/installed.json, классы из vendor), и stdout команд baseline. Унаследованное от оболочки 2>&1 не является вторым названным адресатом. Символьные устройства, например терминал или /dev/null, могут совпадать. Отсутствующий родитель, каталог вместо файла, недоступный путь, закрытый дескриптор и ошибка записи дают код 3. Причина различает неверный ввод и отказ среды. Если stdout недоступен для ответа об ошибке записи отчёта, отказ поступает в stderr.

--group-by

Группировка нарушений в выводе. Значение по умолчанию зависит от форматтера.

bin/qmx check src/ --format=text --detail=all --group-by=rule

Доступные значения: none, file, rule, severity, class, namespace.

--format-opt

Передача специфичных для форматтера опций в формате key=value. Можно указывать несколько раз:

bin/qmx check src/ --format-opt=key=value

Ключ, который не читает ни один форматтер, отвергается с кодом 3. Ключ, который читает другой форматтер, по-прежнему принимается, поэтому скрипт, прогоняющий один набор опций по нескольким форматам, продолжает работать. Каждый ключ можно написать один раз: --format-opt=violations=2 --format-opt=violations=1 отвергается с кодом 3, а не выигрывает последнее значение. Каждая пара проверяется в том виде, в каком написана, поэтому неразбираемое значение отвергается, даже если его заменила бы другая пара или --all. Так же отвергаются два ключа, задающие одно значение: violations рядом с limit или limit рядом с --all (который пишет violations=all).

Опции формата JSON:

Опция По умолчанию Описание
violations=N\|all all Макс. кол-во нарушений в выводе (0=нет)
limit=N\|all all То же значение, что violations, но 0 означает «без ограничения»; пишите один из двух
top=N 10 Количество худших нарушителей
rank-by=score\|density score Упорядочить худших нарушителей по возрастанию health-балла (по умолчанию) или убыванию плотности нарушений
bin/qmx check src/ --format=json --format-opt=limit=100
bin/qmx check src/ --format=json --format-opt=violations=all
bin/qmx check src/ --format=json --format-opt=rank-by=density

Опции формата summary:

Опция По умолчанию Описание
top=N 3 Количество худших нарушителей
rank-by=score\|density score Упорядочить худших нарушителей по возрастанию health-балла (по умолчанию) или убыванию плотности нарушений
bin/qmx check src/ --format-opt=rank-by=density

Отбор худших нарушителей использует полную сохранённую популяцию до ранжирования и top. Селекторы неймспейсов объединяются. Для отдельного заголовка class health выборка --class в JSON/summary требует единственного точного объявления; несколько объявлений логического имени дают отказ с кодом 3 с перечнем точных объявлений. Чтобы сохранить все их точные записи offender, используй --namespace. rank-by=count отвергается с кодом 3; используй score или density. Summary показывает настоящий остаток и советует --format-opt=top=<total>.

Два несвязанных top

--format-opt=top=N (форматы JSON и summary) ограничивает списки худших пространств имён/классов. Глобальный флаг --top — другая опция: он ограничивает отдельный список «Top issues by impact». Их можно задавать независимо друг от друга.

Опции формата health:

Опция По умолчанию Описание
contributors=N 3 Сколько худших вкладчиков показывать для каждого измерения

Опции формата HTML:

Опция По умолчанию Описание
project-name=NAME автоопределение Переопределяет имя проекта в HTML-отчёте
bin/qmx check src/ --format=html --format-opt=project-name="My Project" -o report.html

--fail-on

Минимальный уровень нарушения, при котором возвращается ненулевой код выхода. По умолчанию: error.

# Поведение по умолчанию: ошибка только при error, предупреждения допускаются
bin/qmx check src/

# Ошибка и при warning (для строгого контроля качества)
bin/qmx check src/ --fail-on=warning

# Никогда не завершать с ошибкой из-за нарушений
bin/qmx check src/ --fail-on=none

Предупреждения по-прежнему отображаются в выводе, но по умолчанию не приводят к ненулевому коду завершения. Используйте --fail-on=warning, если хотите, чтобы предупреждения также блокировали CI.

Также можно задать в qmx.yaml:

fail_on: warning   # также ошибка при warning

--exclude-health

Исключить конкретные измерения здоровья из оценки. Исключённые измерения не отображаются в сводке здоровья и не влияют на общую оценку. Можно указывать несколько раз:

# Исключить типизацию из оценки здоровья
bin/qmx check src/ --exclude-health=typing

# Исключить несколько измерений
bin/qmx check src/ --exclude-health=typing --exclude-health=maintainability

Доступные измерения: complexity, cohesion, coupling, typing, maintainability.

Также можно задать в qmx.yaml:

exclude_health:
  - typing

--detail

Добавляет после сводки группированный список нарушений; значение — необязательный потолок его длины. Опция не указана — списка нет (если не заданы --namespace или --class); указана без значения — до 200 нарушений; --detail=N — не больше N; --detail=all или --detail=0 — без потолка. Действует только на формат summary.

# Лимит по умолчанию (200 нарушений)
bin/qmx check src/ --detail

# Показать все нарушения (без лимита)
bin/qmx check src/ --detail=all

# Пользовательский лимит
bin/qmx check src/ --detail=50

Автоматически включается при использовании --namespace или --class.

--top

Количество самых значимых по влиянию находок. По умолчанию: 10; 0 отключает секцию.

# По умолчанию: топ-10
bin/qmx check src/

# Показать топ-25
bin/qmx check src/ --top=25

# Отключить секцию
bin/qmx check src/ --top=0

Управляет секцией «Top issues by impact» формата summary и ключом topIssues формата --format=json — списком находок, ранжированных по влиянию (сочетание ClassRank, серьёзности и времени на исправление), отдельным от списков худших пространств имён и худших классов. Больше ни один формат её не показывает.

Это другая опция, чем --format-opt=top=N, которая ограничивает списки худших нарушителей — см. таблицы опций форматов выше.

--all

Показать все нарушения без усечения. Сокращение для --format-opt=violations=all --detail=all.

# Все нарушения в формате JSON
bin/qmx check src/ --format=json --all

# Все нарушения в формате summary
bin/qmx check src/ --all

Не может быть объединён с --format-opt=violations=N (числовой лимит) и с --detail/--detail=N (ограниченный список; --detail без значения — это лимит 200): каждое такое сочетание отклоняется с кодом 3 до анализа, а не решается молчаливой победой одного из двух. Совместное использование --all с --format-opt=violations=all, --detail=all или --detail=0 допустимо (они синонимы).

--namespace

Фильтрация вывода явным селектором неймспейса. exact: выбирает один неймспейс, subtree: — его и потомков по границам, regex: — фрагмент PCRE без разделителей. Bare- и пустые значения отвергаются; regex всегда сопоставляется со всем неймспейсом.

bin/qmx check src/ --namespace='subtree:App\Service'
bin/qmx check src/ --namespace='regex:App\\(?:Billing|Sales)\\Order'

Фильтрует нарушения и худших нарушителей по выбранным пространствам имён. Показывает оценки здоровья поддерева. Автоматически включает --detail.

Находки уровня проекта (architecture.coverage-gap и прочие диагностики, судящие о прогоне целиком) не выбираются селектором неймспейса: они не принадлежат ни одному пространству имён.

Находки детекторов с именованным объявлением используют пространство имён этого объявления. Находки с файловым субъектом пока проходят через прежнюю логику выбора по пространству имён: одного пути файла недостаточно, чтобы гарантировать их появление в drill-down соответствующего пространства имён.

То же правило сопоставления действует для drill-down по здоровью и списков худших нарушителей, которые включает эта опция, и для опции include_namespaces правила coupling.distance.

Паттерн, не выбравший ни одного проанализированного пространства имён, отвергается с кодом 3, и отказ называет, сколько пространств имён у прогона было. Паттерн, который что-то выбрал и всё равно ничего не сообщил, печатает обычный пустой результат — именно эти два исхода и важно различать.

Взаимоисключающий с --class. Отклоняется с кодом 3 до анализа под --format=gitlab или --format=checkstyle, в том числе когда формат выбран файлом конфигурации: их потребители читают каждую запись как находку, поэтому ни один из них не может сказать, что отчёт — частичный вид.

--class

Фильтрация вывода по конкретному классу с точным совпадением FQCN.

bin/qmx check src/ --class=App\\Service\\UserService

Фильтрует нарушения по указанному классу. Автоматически включает --detail.

FQCN, не совпавший ни с одним проанализированным классом, отвергается с кодом 3 по той же причине, что и --namespace: иначе пустой отчёт читается как чистый класс.

Взаимоисключающий с --namespace. Под gitlab и checkstyle отклоняется так же, как --namespace.


Опции кэширования

Qualimetrix кэширует разобранные AST-деревья для ускорения повторных запусков. По умолчанию кэш находится в пользовательском каталоге платформы под qmx и общий для проектов и worktree этого пользователя; старые записи .qmx-cache внутри checkout не читаются. Поддерживаемый POSIX-абсолютный XDG_CACHE_HOME имеет приоритет; иначе Linux/BSD используют $HOME/.cache, macOS — $HOME/Library/Caches, а ветка Windows читает LOCALAPPDATA. Пути с буквой диска и UNC текущая грамматика не поддерживает. Непригодное умолчание отключает кэш с одним предупреждением.

--no-cache

Полностью отключить кэширование:

bin/qmx check src/ --no-cache

--cache-dir

Указать каталог кэша, который разрешается в поддерживаемый POSIX-путь вне проекта. Относительный путь разрешается от корня проекта: например, ../external-cache подходит, если оказывается вне проекта. По умолчанию используется пользовательский каталог под qmx. Когда корень проекта — / (например, при запуске cron из /), вложенность не проверяется; остальные проверки расположения продолжают действовать.

bin/qmx check src/ --cache-dir=/tmp/qmx-cache

Когда кэширование включено или --clear-cache использует каталог, путь проверяется без создания каталогов. --no-cache без очистки не проверяет неиспользуемый корень кэша. Явный путь внутри проекта, корень другого владельца или с доступом на запись группе либо остальным, как и путь без доступного для записи и поиска каталога, тогда отклоняется с кодом 3. Проверка корня не удостоверяет доверие ко всем предкам. Непригодный неявный каталог по умолчанию выключает кэш и вызывает одно предупреждение. Пригодный каталог создаётся после остальных проверок ввода.

--clear-cache

Очистить кэш перед запуском анализа:

bin/qmx check src/ --clear-cache

Очистка начинается после проверок ввода и подготовки адресатов. Цель или её временный сосед внутри физического корня кэша отклоняются до очистки и анализа, в том числе через символическую ссылку. Если запись кэша не удаётся удалить, команда выдаёт ошибку среды с кодом 3, каталогом, числом оставшихся записей и причиной. При неполной очистке сообщение «Cache cleared.» не выводится. Очистка удаляет только записи qmx, но всех проектов в этом пользовательском корне. Записи, не читавшиеся 30 дней, удаляются постепенно. При каждом открытии проверяются 16 из 256 сегментов; после 16 успешных шагов целевой объём каждого формата — 2 ГиБ плюс записи, добавленные после последней очистки своего сегмента, и по одной самой новой записи сверх лимита в каждом сегменте. Это не мгновенный жёсткий предел. Временные файлы публикации удаляются по возрасту после 30 дней; свежие сохраняются при квотной очистке, чтобы не лишать активную запись её имени. Их объём добавляется к целевому объёму записей кэша. Старые временные файлы в каталоге метаданных формата тоже удаляются. Если посторонние данные удерживают отделённый каталог, очистка сохраняет их и сообщает отказ вместо «Cache cleared». Следующая очистка повторно обрабатывает оставшиеся отделённые каталоги.


Опции baseline

Полный жизненный цикл и формат файла описаны в Baseline.

--baseline=BASELINE

Использовать файл baseline, чтобы применить принятые потолки к текущим нарушениям:

bin/qmx check src/ --baseline=baseline.json

--show-resolved

Посчитать записи, чья полная идентичность больше не появляется в измеряемом наборе:

bin/qmx check src/ --baseline=baseline.json --show-resolved

Stale требует полного сравнимого отсутствия. Stale/inert публикуют проектный Warning baseline.unused-entry с обычной политикой --fail-on. Группа, которая всё ещё срабатывает с меньшим числом элементов, не считается resolved.

Lifecycle-команды baseline

Ниже приведена полная поверхность команд для записи и проверки baseline:

bin/qmx baseline:generate <baseline> [<paths>...] [--mode=MODE] [--force]
bin/qmx baseline:update   <baseline> [<paths>...] [--force] [--accept-new=CHANNEL]... [--record-exclusions]
bin/qmx baseline:cleanup  <baseline> [<paths>...] [--remove=REMOVE]... [--force]
bin/qmx baseline:explain  <symbol> [<paths>...] [--baseline=BASELINE] [--channel=CHANNEL]
bin/qmx baseline:rename-channels <baseline> <map> [--format=FORMAT]

Первые четыре команды принимают --config=CONFIG, --preset=PRESET, --disable-rule=DISABLE-RULE, --only-rule=ONLY-RULE и --rule-opt=RULE-OPT. Все четыре также принимают --include-generated, --include-autoload-dev, --no-cache, --workers/-w и --memory-limit. Ни одна не принимает опции исключения или suppression. baseline:rename-channels не принимает ни одной из них: она не запускает анализ, поэтому измеряемого набора, который они определяли бы, нет.

  • baseline:generate захватывает текущие измеряемые нарушения. По умолчанию используется --mode=ratchet; --mode=suppress записывает безусловное принятие захваченных идентичностей. Его --force перезаписывает существующий файл.
  • baseline:update только ужесточает существующие записи. Его --force снимает проверку покрытия записанной области.
  • baseline:cleanup по умолчанию выводит кандидатов и удаляет только повторяемые селекторы --remove=REMOVE. Его --force также снимает проверку области.
  • baseline:explain показывает порог из конфигурации, принятую величину baseline и override из исходника для канонического символа; --channel=CHANNEL сужает ответ.
  • baseline:rename-channels переписывает поле channel записей, названных объявленной табличной картой, и больше ничего, не анализируя код. Ошибки содержимого, грамматики и окружения следуют политике отказов команды (код 3); частичная запись не публикуется. См. Перенос baseline на переименованные каналы — учти, что перенос записи меняет её селектор.

Четыре анализирующие команды отказываются классифицировать или записывать baseline при неполном анализе и завершаются с кодом 4. --force снимает только ограничения файла/области; он не делает частичный набор измерений допустимым. Существующий файл остаётся побайтово неизменным, а baseline:generate не создаёт отсутствующий файл.

Загружаемые версии baseline и процедура миграции старого файла описаны в разделе Замена старого baseline.

Удалённые опции --generate-baseline и --baseline-ignore-stale не имеют алиасов. Используй вместо них baseline:generate и явный baseline:cleanup --remove.


--accept-new=CHANNEL и --record-exclusions

Несовместимые режимы baseline:update. Повторяй --accept-new с точными выбранными объявленными каналами: добавляются только новые полные сравнимые измеренные identity, старые границы/modes сохраняются. Wildcard, уровни, необъявленные, configuration-error и audit каналы отклоняются с 3 до анализа. --record-exclusions требует точно записанные пути даже с --force, записывает полное определение и перезахватывает только затронутые полные сравнимые группы с modes. Недоступные доказательства запрещают всю запись. Обычный update сохраняет scope/exclusions; равное принятие unchanged, no-op сохраняет байты/generated. Пять читателей выполняют preflight документа один раз до анализа/ переноса: грамматика рано, настроенная семантика позже. Неполный анализ — 4 до записи. Stale требует полного сравнимого отсутствия; stale/inert дают проектный Warning baseline.unused-entry с обычной политикой --fail-on.

Опции подавления

--show-suppressed

Показать нарушения, подавленные тегами @qmx-ignore, а также нарушения, подавленные записью suppress_namespaces / suppress_namespace_channels / suppress_paths на уровне правила в qmx.yaml (см. «Правила»):

bin/qmx check src/ --show-suppressed

Независимо от --show-suppressed, запуск с -v печатает разбивку по правилам — сколько нарушений подавлено таким образом. Namespace-бакет включает обе опции неймспейсов и выводится отдельно от suppress_paths; каждый бакет разбит по имени правила. В отличие от @qmx-ignore, в остальном это подавление проходит незаметно — ничто в стандартном выводе не сигнализирует о том, что оно произошло.

--show-suppressed выводит прозой лишь часть этого. --format=suppressed публикует полный состав — все восемь механизмов подавления, а не только эти два, — как машиночитаемый JSON; см. «Форматы вывода». Для взведения per-rule-захвата достаточно либо --show-suppressed, либо выбора --format=suppressed (в том числе format: suppressed в qmx.yaml) — оба вместе не нужны. В остальном эти две поверхности не эквивалентны — что показывает каждая, см. в разделе suppressed.

Suppression composition включает восемь механизмов, включая снятие реально порождённых находок механизмом selection. Producer, который не исполнялся, ничего не породил для снятия и описан отдельно в notRun, не в byMechanism. Threshold-audit effects, усечение форматтером и namespace/class drill-down сохраняют отдельный смысл; усечение/drill-down меняют представление, а не identity исходных находок.

--no-suppression-annotations

Выводить все нарушения, включая те, которые подавлены тегами @qmx-ignore:

bin/qmx check src/ --no-suppression-annotations

Опция не меняет то, что измеряет baseline

Флаг влияет только на отчёт. Baseline измеряет те нарушения, которые оставляют конфигурация и аннотации в исходниках, поэтому нарушение, убранное тегом @qmx-ignore, никогда не попадает в baseline и никогда не сравнивается с ним — независимо от того, передан ли этот флаг.

Видимое следствие: под этим флагом подавленное аннотацией нарушение показывается со своей собственной серьёзностью и никогда не повышается до ошибки, потому что ни одна запись baseline его не покрывает. Флаг может сузить измеряемое baseline множество (--suppress-path, --suppress-namespace), но расширить его не может ни один.


Опции области Git

Публикация находок относительно изменённых файлов с сохранением объявленной project-scoped диагностики, в том числе циклов архитектуры. Нарушение слоя сохраняется только при изменении source-файла в обоих режимах. Полное руководство смотрите в разделе Интеграция с Git.

--report

Ограничивает публикацию по Git, сохраняя выбранные пути анализа. Обычный режим также сохраняет соответствующие namespace/project находки; объявленные project-scoped находки остаются видимыми:

bin/qmx check src/ --report=git:main..HEAD
bin/qmx check src/ --report=git:origin/develop..HEAD

--report-strict

Ограничивает file-scoped находки изменёнными файлами без namespace/project расширения. Объявленные project-scoped находки, включая циклы архитектуры, сохраняются и в strict-режиме. Нарушения слоёв фильтруются по source-файлу:

bin/qmx check src/ --report=git:main..HEAD --report-strict

Опции выполнения

--workers, -w

Управление параллельной обработкой. По умолчанию: автоопределение по количеству CPU.

# Отключить параллельную обработку (один процесс)
bin/qmx check src/ --workers=1

# Отключить параллельную обработку (последовательно)
bin/qmx check src/ --workers=0

# Использовать ровно 4 воркера
bin/qmx check src/ --workers=4

Совет

Используйте --workers=1 для отладки или в однопроцессном окружении. --workers=0 отключает параллелизм (последовательное выполнение); автоопределение действует, когда опция не задана. Транспорт использует процессы, а не потоки или fork. Нужны proc_open и, вне Windows, ext-posix. На подходящем прогоне явное значение больше одного даёт отказ среды с кодом 3, если первый воркер не стартует или не отвечает за 10 секунд; автоматический выбор предупреждает и переходит к последовательной работе. NUMBER_OF_PROCESSORS читается только на Windows и там должен быть положительным десятичным целым.

--memory-limit

Установить лимит памяти PHP для анализа. По умолчанию используется значение memory_limit из php.ini.

Лимит действует и в рабочих процессах (см. --workers), где файлы разбираются и измеряются. Рабочий процесс, которому не хватило памяти, проваливает файл, который обрабатывал: прогон сообщает этот файл как необработанный, завершается кодом 4, и сообщение о сбое называет лимит, с которым работали процессы; собственная строка PHP «Allowed memory size … exhausted» появляется в stderr.

# Установить лимит памяти 1ГБ для больших проектов
bin/qmx check src/ --memory-limit=1G

# Без ограничений памяти
bin/qmx check src/ --memory-limit=-1

Допустимые форматы: -1 (без ограничений) или положительное целое с необязательным суффиксом K/M/G (например, 512M, 2G). 0, ведущий ноль (010M, который PHP считал бы восьмеричным) и значение свыше PHP_INT_MAX байт отклоняются с кодом 3. OOM координатора после связывания диагностики и выделения резерва даёт код 4 с лимитом и источником; более ранний чужой shutdown callback может заменить последнюю ошибку PHP до её чтения.

Эквивалент в YAML: memory_limit: 1G

--log-file

Записывать лог прогона в файл, по одной JSON-записи на строку:

bin/qmx check src/ --log-file=qmx.log

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

Действуют те же правила ссылок, дескрипторов и совпадений адресатов, что для --output. Недоступный для записи адресат отклоняется с кодом 3. При ошибке записи во время анализа логгер запоминает первую причину и считает потерянные записи; команда сообщает ошибку среды до публикации отчёта. Неполная строка может остаться. Пустое или пробельное значение, в том числе --log-file=$LOG при незаданной переменной, отклоняется с кодом 3. Чтобы не писать файловый лог, не указывайте опцию. Опцию принимает только check.

--log-level

Установить минимальный уровень строк лога — для файла --log-file и для консоли:

bin/qmx check src/ --log-file=qmx.log --log-level=debug

Доступные уровни: debug, info, warning, error. Значение вне этого набора отвергается с кодом 3, а не откатывается к значению по умолчанию.

Задано Консоль --log-file
ничего warning; с -v — info; с -vv — debug info
уровень, с -v и выше этот уровень этот уровень
уровень, без -v этот уровень, если он строже warning, иначе warning этот уровень

Без -v уровень может только сузить консоль: --log-level=error скрывает предупреждения, а --log-level=debug --log-file=qmx.log пишет подробный файл и оставляет терминал таким же тихим, как был. -q глушит консольные логи при любом уровне, но ответы команд и сообщения о завершении остаются; файл продолжает получать строки.

--no-progress

Отключить прогресс-бар. Полезно в CI-пайплайнах:

bin/qmx check src/ --no-progress

Принимается каждой командой, которая показывает прогресс-бар: check, directives, debug:layer-assignment, baseline:generate, baseline:update, baseline:cleanup и baseline:explain. graph:export тоже анализирует дерево, но бара не рисует, поэтому опции у него нет.

Прогресс-бар пишется в поток ошибок, поэтому отчёт в стандартном выводе остаётся машиночитаемым даже на терминале — bin/qmx check src/ --format=json > report.json даёт валидный JSON и без этого флага. Бар рисуется, только если поток ошибок — терминал; перенаправление потока ошибок гасит его, не трогая отчёт.

Бар делит поток ошибок с подробным логом (-v, -vv, -vvv) и с предупреждениями во время прогона. И то и другое рисуется через одного владельца: строка диагностики сдвигает бар вниз и остаётся на экране, а бар перерисовывается под ней. Поэтому повышение подробности бар не выключает, а бар не съедает строки лога.

--silent, -q/--quiet

Флаги Symfony Console, подавляющие обычный вывод. Оба принимаются любой командой:

bin/qmx check src/ --silent
bin/qmx check src/ -q

--silent и -q/--quiet подавляют progress и статусные логи, но сохраняют ответ отвечающей команды и сообщения о завершении. SHELL_VERBOSITY=-1 или -2 ведёт себя так же. Отказ из-за ввода по-прежнему пишет причину в stderr для текстовых форматов, а JSON-форматы публикуют JSON-конверт ошибки в stdout; успешный check --format=json выводит полный JSON в stdout. Если нужен только код, перенаправьте stdout; stderr перенаправляйте, только если диагностика не нужна.


Опции профилирования

--profile

Включить внутренний профайлер. Опционально можно указать файл для сохранения профиля:

<!-- llms:skip-end -->

# Показать сводку профилирования на экране
bin/qmx check src/ --profile

# Сохранить профиль в файл
bin/qmx check src/ --profile=profile.json

Цель, в которую нельзя записать, отклоняется с кодом 3 до анализа по тем же правилам адресата, что и --output. Пустое --profile= также отклоняется. Отказ до начала анализа, включая неверный baseline, не публикует профиль. Если анализ начался и команда дошла до своего завершения, профиль публикуется до отчёта; параллельный прогон включает collection.workers. Сбой записи профиля проходит через конверт ошибки прогона вместо успешного отчёта в stdout. OOM координатора до публикации профиля не создаёт новый файл. Профиль, опубликованный до более позднего OOM отчёта, остаётся: опубликованные адресаты не откатываются. Неопубликованные именованные адресаты освобождаются на связанном OOM-пути. Эта гарантия начинается после связывания диагностики и выделения резерва.

--profile-format

Выбор формата экспорта профиля. По умолчанию: json. Любое другое значение отклоняется с кодом 3 до начала анализа — независимо от того, указан ли файл в --profile.

bin/qmx check src/ --profile=profile.json --profile-format=chrome-tracing

Доступные форматы: json, chrome-tracing.

Совет

Используйте формат chrome-tracing и откройте файл в Chrome DevTools (chrome://tracing) для визуального анализа производительности.


Опции правил

--disable-rule

Отключить правило-производитель, целую группу или отдельный канал нарушения. Селектор — это либо точное имя (правило-производитель или канал), либо X.* строго для потомков X — сам X в это не входит; группа выбирается только так (complexity.*). Голый префикс без звёздочки — ошибка. Селектор канала можно сузить до одного уровня дерева агрегации через :level, как и у --only-rule. Отключение одного канала не останавливает производителя, чтобы остальные его каналы продолжали попадать в отчёт. Опцию можно указывать несколько раз:

# Отключить одно правило
bin/qmx check src/ --disable-rule=size.class-count

# Отключить все правила сложности
bin/qmx check src/ --disable-rule=complexity.*

# Отключить несколько
bin/qmx check src/ --disable-rule=complexity.* --disable-rule=cohesion.lcom

# Отключить только один канал computed finding
bin/qmx check src/ --disable-rule=health.complexity

Сбой из-за нехватки памяти в Duplication

Если PHP исчерпает память во время duplication.clone, детектор выведет в stderr короткую диагностику с местом сбоя и текущим memory_limit, предложит --memory-limit или memory_limit в qmx.yaml и завершится с кодом 4. Фатальная нехватка памяти может прервать вывод отчёта; валидный или полный JSON не гарантируется. Поздний отказ чтения также делает прогон неполным с кодом 4 и очищает частичный результат Duplication. Пустой результат такого прогона не доказывает отсутствие копий. Чтобы намеренно пропустить обнаружение, отключи само duplication.clone.

--only-rule

Запустить только подходящие правила-производители или каналы нарушений. Селектор — это либо точное имя (правило-производитель или канал), либо X.* строго для его потомков — единственный способ выбрать группу; каждое из них можно сузить до одного уровня дерева агрегации через :level. Селектор с уровнем не останавливает своего производителя: отфильтрованный производитель никогда не выдал бы запрошенный уровень. Опцию можно указывать несколько раз:

# Запустить только правила сложности
bin/qmx check src/ --only-rule=complexity.*

# Запустить два конкретных правила
bin/qmx check src/ --only-rule=complexity.ccn --only-rule=size.method-count

# Выбрать один канал встроенного измерения здоровья: производитель и канал
# называются одинаково, потому что каждое из шести измерений — сам себе производитель
bin/qmx check src/ --only-rule=health.complexity

Селектор должен точно совпасть с зарегистрированным producer или выводимым каналом, либо X.* должен разрешиться хотя бы в одного потомка. Неизвестный селектор — включая голый префикс без звёздочки или X.*, не совпавший ни с чем, — завершается с кодом 3 до записи report-payload в stdout. Если написание со звёздочкой что-то выбрало бы, отказ его называет:

Rule selector "complexity" does not match any registered producer or channel. Write "complexity.*" to select its descendants.

Единственное голое слово, которое принимается, — computed: это имя производителя, а не группы.

Аналогично, владелец перед : в --rule-opt=RULE:OPTION=VALUE должен быть точным producer-rule, а не группой или каналом — группа или канал здесь являются ошибкой. То же правило действует и для ключей секции rules: в YAML.

Роль selection объявлена для каждого канала

annotation.unresolved-directive и annotation.unused-directive выбираются напрямую. Unsupported/invalid thresholds следуют addressed producer. Явный disable annotation.directive останавливает producer. Применимость path/namespace exclusions остаётся отдельным вопросом.

--rule-opt

Переопределить опции правил из командной строки. Формат: rule-name:option=value, где rule-name должен быть точным producer-rule — никогда группой, никогда каналом и никогда wildcard. То же ограничение точного producer действует для ключей rules: в YAML. Selection с :level адресует объявленный channel code, а не иначе названного producer. Опцию можно указывать несколько раз:

bin/qmx check src/ --rule-opt=complexity.ccn:callable.warning=15
bin/qmx check src/ --rule-opt=complexity.ccn:callable.error=30

Все три способа ошибиться отвергаются с кодом 3 там, где раньше пара опций молча отбрасывалась: значение, записанное без =VALUE; имя правила, которому не отвечает ни один зарегистрированный producer; и имя опции, которого это правило не принимает. В последнем случае отказ перечисляет опции, которые правило принимает.

suppress_namespace_channels настраивается в YAML, а не через --rule-opt: каждому селектору нужен непустой список паттернов неймспейсов, а channel-keyed dictionaries не являются объявленными dotted option addresses CLI. Его ключи — это селекторы каналов, подчиняющиеся тому же правилу «точное имя или X.*», что и @qmx-ignore: голый префикс вроде health теперь ошибка, а не сокращение для health.*. Ключ может добавить :namespace и никакой другой уровень: опции достаются только агрегаты по неймспейсам, поэтому любой другой уровень назвал бы фильтр, который не сработает никогда.

Быстрые флаги для правил

Для многих правил доступны специальные CLI-флаги для быстрой настройки опций:

Флаг Правило Опция
--cyclomatic-warning=N complexity.ccn callable.warning
--cyclomatic-error=N complexity.ccn callable.error
--cyclomatic-class-warning=N complexity.ccn class.max_warning
--cyclomatic-class-error=N complexity.ccn class.max_error
--cognitive-warning=N complexity.cognitive callable.warning
--cognitive-error=N complexity.cognitive callable.error
--cognitive-class-warning=N complexity.cognitive class.max_warning
--cognitive-class-error=N complexity.cognitive class.max_error
--npath-warning=N complexity.npath callable.warning
--npath-error=N complexity.npath callable.error
--npath-class-warning=N complexity.npath class.max_warning
--npath-class-error=N complexity.npath class.max_error
--wmc-warning=N complexity.wmc warning
--wmc-error=N complexity.wmc error
--wmc-exclude-data-classes complexity.wmc excludeDataClasses
Флаг Правило Опция
--cbo-warning=N coupling.cbo class.warning
--cbo-error=N coupling.cbo class.error
--cbo-ns-warning=N coupling.cbo namespace.warning
--cbo-ns-error=N coupling.cbo namespace.error
--distance-warning=N coupling.distance max_distance_warning
--distance-error=N coupling.distance max_distance_error
--instability-class-warning=N coupling.instability class.max_warning
--instability-class-error=N coupling.instability class.max_error
--instability-ns-warning=N coupling.instability namespace.max_warning
--instability-ns-error=N coupling.instability namespace.max_error
--class-rank-warning=N coupling.class-rank warning
--class-rank-error=N coupling.class-rank error
Флаг Правило Опция
--class-count-warning=N size.class-count warning
--class-count-error=N size.class-count error
--method-count-warning=N size.method-count warning
--method-count-error=N size.method-count error
--property-count-warning=N size.property-count warning
--property-count-error=N size.property-count error
Флаг Правило Опция
--dit-warning=N design.dit warning
--dit-error=N design.dit error
--lcom-warning=N cohesion.lcom warning
--lcom-error=N cohesion.lcom error
--lcom-min-methods=N cohesion.lcom minMethods
--lcom-exclude-readonly cohesion.lcom excludeReadonly
--lcom-exclude-methods='[NAME]' cohesion.lcom excludeMethods
--noc-warning=N design.noc warning
--noc-error=N design.noc error
--param-type-coverage-warning=N design.type-coverage.param warning
--param-type-coverage-error=N design.type-coverage.param error
--return-type-coverage-warning=N design.type-coverage.return warning
--return-type-coverage-error=N design.type-coverage.return error
--property-type-coverage-warning=N design.type-coverage.property warning
--property-type-coverage-error=N design.type-coverage.property error
--property-exclude-readonly size.property-count excludeReadonly
--property-exclude-promoted-only size.property-count excludePromotedOnly
Флаг Правило Опция
--mi-warning=N maintainability.mi warning
--mi-error=N maintainability.mi error
--mi-min-statements=N maintainability.mi minStatements
--mi-exclude-tests maintainability.mi excludeTests
Флаг Правило Опция
--constructor-overinjection-warning=N code-smell.constructor-overinjection warning
--constructor-overinjection-error=N code-smell.constructor-overinjection error
--data-class-woc-threshold=N design.data-class wocThreshold
--data-class-wmc-threshold=N design.data-class wmcThreshold
--data-class-min-members=N design.data-class minMembers
--data-class-exclude-readonly design.data-class excludeReadonly
--data-class-exclude-promoted-only design.data-class excludePromotedOnly
--data-class-exclude-exceptions design.data-class excludeExceptions
--god-class-wmc-threshold=N design.god-class wmcThreshold
--god-class-lcom-threshold=N design.god-class lcomThreshold
--god-class-tcc-threshold=N design.god-class tccThreshold
--god-class-class-loc-threshold=N design.god-class classLocThreshold
--god-class-min-criteria=N design.god-class minCriteria
--god-class-min-methods=N design.god-class minMethods
--god-class-exclude-readonly design.god-class excludeReadonly
--long-parameter-list-warning=N code-smell.long-parameter-list warning
--long-parameter-list-error=N code-smell.long-parameter-list error
--long-parameter-list-vo-warning=N code-smell.long-parameter-list vo-warning
--long-parameter-list-vo-error=N code-smell.long-parameter-list vo-error
--unreachable-code-warning=N code-smell.unreachable-code warning
--unreachable-code-error=N code-smell.unreachable-code error
Флаг Правило Опция
--circular-deps architecture.circular-dependency enabled
--max-cycle-size=N architecture.circular-dependency maxCycleSize
--layer-violation architecture.layer-violation enabled
--layer-violation-severity=SEVERITY architecture.layer-violation severity
--unassigned-class-mode=MODE architecture.unassigned-class mode

Другие команды

baseline:cleanup

Проверить stale-кандидатов в baseline. Без --remove команда только выводит их и никогда не меняет файл; удалить явно проверенный selector можно так, как описано в Baseline:

bin/qmx baseline:cleanup baseline.json src/
bin/qmx baseline:cleanup baseline.json src/ --remove=<selector>

debug:layer-assignment

bin/qmx debug:layer-assignment 'App\Service\Foo' --format=json
bin/qmx debug:layer-assignment 'app\service\foo' --config qmx.yaml
Опция Значение
-c, --config=FILE Файл конфигурации; по умолчанию qmx.yaml.
--preset=PRESET Именованный или файловый preset; можно повторять.
--format=FORMAT text (по умолчанию) или json.

Команда выполняет обычные Discovery/Collection и ищет имя среди наблюдённых объявлений и graph ends; install-only классы не добавляются. ASCII-регистр разрешается в наблюдённое написание, high-byte имена parser принимаются. Только пустое нормализованное имя отвергается до анализа; прочий неизвестный ввод даёт exit 3 после lookup, даже при выключенной политике. Информационный ответ даёт exit 0. Настройте выключение трёх layer-policy producers в YAML; --disable-rule команды check здесь не добавлен.

JSON содержит meta, канонический fqn, assigned, contendingMatches, shadowed, shadowedBy, undecided, contenders, chainStopsAt, hasLayers, policyDisabled, edgeEndOnly. Shadow verdict публикует точное exemption при наличии; при disabled policy нет reported/exemption или diagnostic/docs hint. Полная семантика и нативный пример — в Architecture. Ошибки JSON заменяют ответ стандартным error/exit_code envelope.

directives

Показать, что на самом деле делает каждая инлайновая директива @qmx-ignore и @qmx-threshold в анализируемом дереве. Подавление оценивается по тому, что оно погасило; пороговая директива — снятием и повторным исполнением правил поверх измерений того же прогона, по умолчанию только того правила, которое она адресует, — одно исполнение на директиву.

bin/qmx directives src/

# Переисполнить все включённые правила, а не только адресуемое — контроль, которым проверяется узкий проход по умолчанию
bin/qmx directives src/ --sweep=full

# Машиночитаемый вывод — для агентов, скриптов и CI
bin/qmx directives src/ --format=json
Опция Описание
-c, --config=FILE Путь к qmx.yaml (по умолчанию qmx.yaml в текущем каталоге)
--format=FORMAT text (по умолчанию) или json
--sweep=SCOPE Сколько правил переисполняет каждая контрфактическая проверка: narrow (по умолчанию) или full
--preset=PRESET Применить именованный пресет (можно повторять)
--only-rule=RULE Судить по прогону, в котором работали только эти правила (можно повторять)
--disable-rule=RULE Судить по прогону с выключенными правилами (можно повторять)
--rule-opt=RULE:OPT=VAL Судить по прогону с этой опцией правила (можно повторять)
--no-cache Не читать и не писать кэш AST
--cache-dir=DIR Каталог кэша AST, проверяется как у check
-w, --workers=N Параллельные воркеры (0 — последовательно)
--memory-limit=LIMIT Лимит памяти PHP, например 512M или -1

Четыре опции селекции нужны потому, что вердикт относителен прогону: указывайте те же правила и границы, с которыми проверяет ваш CI, иначе ответ будет про другой прогон.

@qmx-threshold называет ровно одно правило, поэтому при --sweep=narrow контрфактическая проверка переисполняет только его. --sweep=full переисполняет все включённые правила ради тех же вердиктов, но заметно дороже — это не медленный запасной вариант, а контроль, которым измеряется, а не предполагается, что снятие директивы одного правила не может сдвинуть находки другого: оба охвата прогоняются по одному дереву и сравниваются вердикт к вердикту. На собственном src/ этого проекта узкий охват в несколько раз дешевле, и оба охвата совпадают по каждому вердикту. И текстовый отчёт, и --format=json указывают, каким охватом получены вердикты.

Опции исполнения значат то же, что у check (--no-cache, --cache-dir, --workers, --memory-limit), поэтому аудит можно запускать изолированно от общего кэша: bin/qmx directives src/ --no-cache --workers=0.

Коды возврата: 0 — нет публикуемого отказа или наблюдаемой inert-директивы, включая полный намеренно пустой исключённый набор; 2 — есть публикуемый отказ или inert с наблюдаемой границей; 3 — ошибка ввода/конфигурации, включая действительно пустое дерево; 4 — неполный прогон; 5 — непредвиденный внутренний сбой команды. Неполнота имеет приоритет. Text и JSON сохраняют все места, включая отказы, каналы которых итоговая селекция не публикует. Измеренная пометка охвата есть в тексте и JSON scope.note. JSON также публикует измеренный охват проекта в scope.project_scope: состояние, неизмеренные каналы и причины источников.

Вердиктов пять:

Вердикт Что он утверждает
effective Подавлена произведённая находка или снятие меняет результат threshold.
applied-boundary-only Директива применилась; изменилась лишь граница в находке (JSON: overrun).
inert Ничего не подавлено или снятие ничего не меняет; код 2 только при наблюдаемой границе.
unmeasured Producer не исполнялся, субъект не покрыт либо threshold перекрыт другой директивой.
refused Директива недопустима или неприменима, с непустым списком причин отказа.

Каждый прочитанный тег имеет одно место независимо от числа привязок. Иначе неиспользуемое подавление остаётся unmeasured, если прогон не может судить о субъекте производителя. Узкий прогон не доказывает неиспользуемость объявления зависимого от запуска канала; проанализированный локальный участник по-прежнему может быть измерен. Позиции подавления/диагностики различают одинаковые комментарии на строке; JSON по-прежнему публикует file, line, form и target, а не внутреннюю позицию. Для next-line line — строка тега, а не цель после комментария. Места отказа несут обязательный refusals: [{channel, message}]; прочие исходы — пустой список. reason описывает только Unmeasured, при необходимости с masked_by. Ни JSON отказа, ни JSON места не публикуют внутренний addressed producer.

Вердикт относителен анализируемому охвату

Порог на метрике, вычисляемой по проанализированному подграфу, — прежде всего связность — бывает живым по всему проекту и мёртвым по одному его каталогу, и оба ответа верны. Указывайте команде то, что проект действительно анализирует. Отчёт печатает охват, в котором он измерял, а прогон, не разобравший часть дерева, возвращает 4 вместо того, чтобы называть что-либо мёртвым.

Судим по произведённому правилами, а не по отчёту

suppress_paths, suppress_namespaces и suppress_namespace_channels подавляют публикацию, а не измерение. Директива, сдвинувшая находку внутри исключённого неймспейса, всё равно что-то сделала, поэтому аудит задаёт вопрос по всем находкам, произведённым правилами, а не по отчёту. Единственный канал вне этого универсума — annotation.unused-directive, который прогон собирает уже после исполнения правил: адресовать его директива не может, поэтому и судить по нему нечего.

Подавлению не засчитывается гашение ошибки конфигурации (annotation.unresolved-directive и два его собрата). Эти каналы выведены из-под аннотационного подавления по построению; допуск и достижимость могут отказать директиве до оценки её эффекта.

Явный селектор annotation.unused-directive или duplication.clone получает refused после проверки достижимости/уровня. Аудит несёт те же причины отказа, что и check. Общий * и голый file оцениваются как effective/inert по другим находкам и не глушат запрещённые каналы.

Вердикт applied-boundary-only намеренно ничего не утверждает о направлении. У слоя правил нет понятия «строже»: у coupling.instability хуже больше, у cohesion.tcc меньше, — поэтому директива, ужесточающая границу, и директива, поднявшая границу, которую величина уже прошла, дают одно и то же наблюдение. В --format=json этот вердикт сохраняет стабильный ключ overrun.

Если правило не публикует границу вместе с находкой, вердикт inert сопровождается пометкой об этом и не роняет сборку: граница, которую величина уже прошла, выглядела бы точно так же, и требовать удаления директивы значило бы выдать незаданный вопрос за доказанный долг. В --format=json это поле "boundary_observable": false.

При ошибке --format=json печатает в stdout {"error": "...", "exit_code": N, "position": ..., "source": ...} вместо человекочитаемой строки <error>.

graph:export

Команда читает общий документ конфигурации. Без аргументов путей использует настроенные или Composer defaults; применяет exclude и фильтр @generated. Принимает --config, --preset, --exclude, --include-generated, --include-autoload-dev, --no-cache, --workers/-w и --memory-limit. --format/-f выбирает только dot или json независимо от format анализа в документе. У --direction нет короткого алиаса; глобальный -d меняет рабочий каталог.

Экспортировать граф зависимостей для визуализации:

# Экспорт в формате DOT (по умолчанию)
bin/qmx graph:export src/ -o graph.dot

# Экспорт в формате JSON (агрегированный список смежности с метаданными)
bin/qmx graph:export src/ --format=json -o graph.json

# Фильтрация по пространству имён
bin/qmx graph:export src/ --namespace='subtree:App\Service' --namespace='subtree:App\Repository'

# Исключение пространств имён
bin/qmx graph:export src/ --exclude-namespace='subtree:App\Generated'

# Изменение направления графа
bin/qmx graph:export src/ --direction=TB

# Отключение группировки по пространствам имён
bin/qmx graph:export src/ --no-clusters
Опция Описание
-o, --output=FILE Выходной файл (по умолчанию: stdout)
-f, --format=FORMAT dot (по умолчанию) или json
--direction=DIR Направление графа: LR, TB, RL, BT (по умолчанию: LR)
--no-clusters Не группировать узлы по пространствам имён
--namespace=SELECTOR Включить неймспейсы через exact:, subtree: или regex: (можно повторять)
--exclude-namespace=SELECTOR Исключить неймспейсы теми же явными формами (можно повторять)

Любой --namespace или --exclude-namespace должен связаться с исходным graph vertex до фильтрации. Непривязанное значение даёт exit 3; case-only near match советует точное написание графа, но не принимает ошибочный регистр.

Цель --output судится и пишется так же, как check обходится со своим --output: каталог или имя, оканчивающееся на /, недоступный для записи существующий файл и новое имя в каталоге, которого нет или в котором нельзя создать файл, отклоняются с кодом 3 до чтения первого файла. Обычная названная цель подготавливается во временном файле и публикуется атомарно; доверенная символическая ссылка сохраняет свою запись и публикует referent. /dev/stdout и именованные каналы сохраняют потоковую запись. Действует та же граница доступности обработки SIGINT/SIGTERM.

Любой --namespace или --exclude-namespace, не связанный ни с одним исходным graph vertex, отвергается с exit 3 до фильтрации. Обе двери используют одинаковую проверку; case-only near match советует точное написание графа, но не принимает ошибочный регистр.

Если хотя бы один обнаруженный файл не удалось разобрать или обработать, graph:export завершается с кодом 4 и не выводит частичный граф. Команда не создаёт отсутствующий output-файл и побайтово сохраняет существующий.

hook:install

Установить git-хук pre-commit:

bin/qmx hook:install

# Перезаписать существующий хук
bin/qmx hook:install --force

hook:status

Показать текущий статус хука pre-commit:

bin/qmx hook:status

hook:uninstall

Удалить хук pre-commit:

bin/qmx hook:uninstall

# Восстановить оригинальный хук из резервной копии
bin/qmx hook:uninstall --restore-backup

rules

Принимает --config=FILE и повторяемый --preset=PRESET, проверяет весь документ и включает именованные computed metrics. Отмечает правила, отключённые текущей итоговой селекцией only_rules/disabled_rules. Не запрашивает пути анализа: каталог без PHP не мешает показать правила. Ошибочный документ отклоняется с кодом 3. Отдельного CLI-парсера rules: false или enabled: false для этой отметки нет; эти переключатели принадлежат разрешению опций правил.

Вывести список всех доступных правил с описаниями и опциями CLI:

# Показать все правила
bin/qmx rules

# Фильтр по группе
bin/qmx rules --group=complexity

Пример вывода (для --group=complexity):

4 rules available

Complexity
  complexity.ccn                           Checks cyclomatic complexity at method and class levels
    complexity.ccn judges complexity.ccn, complexity.ccn.max
    options: enabled, threshold
    options at callable: enabled, error, threshold, warning
    options at class: enabled, max-error, max-warning, threshold
    --cyclomatic-warning (--rule-opt=complexity.ccn:callable.warning=...)
    --cyclomatic-error (--rule-opt=complexity.ccn:callable.error=...)
    --cyclomatic-class-warning (--rule-opt=complexity.ccn:class.max-warning=...)
    --cyclomatic-class-error (--rule-opt=complexity.ccn:class.max-error=...)
  ...

Every rule also takes: suppress-namespace-channels, suppress-namespaces, suppress-paths

Usage: bin/qmx check --disable-rule=<name> | --only-rule=<name>
        bin/qmx check --rule-opt=<name>:<option>=<value>

Docs: https://qualimetrix.dev · AI agents: https://qualimetrix.dev/llms.txt

Правила сгруппированы по категориям. Строка options: называет то, что правило принимает в своём блоке, а строка options at <уровень>: — то, что принимает слот уровня; это полный набор, независимо от того, есть ли у опции CLI-алиас. Три ключа в подвале допустимы под любым правилом. enabled печатается у каждого правила, включая architecture.unassigned-class: false выключает его даже в reportable mode; явное true с mode: ignore отказывает, потому что producer оставался бы неактивным.

Каждый CLI-алиас показан вместе с длинной формой --rule-opt, в которую он разворачивается. Значения порогов по умолчанию в этот вывод не входят — см. Пороги по умолчанию.

Typed values правил и итоговый selection

--rule-opt и dedicated aliases разбирают одну объявленную YAML-форму значения. Например, --lcom-exclude-methods='[getName, getDescription]' пишет sequence; CSV или scalar не заменяют список. Null не превращается в текст. Две записи одной canonical option через aliases или --rule-opt в одном invocation отказывают. Точка в option address проходит только объявленный level slot, а не произвольный channel-keyed dictionary. suppress_namespace_channels maps пиши в YAML.

Голое имя выбирает точный producer или channel, X.* — строгих потомков. Пара channel-name:level требует, чтобы именно объявленный channel code публиковался на этом уровне. Совпадающие producer/channel names работают как имя канала; отдельного alias producer:level для иначе названных channels нет. Для namespace-channel exclusion тот же свидетель обязан принадлежать указанному producer/множеству.

Сначала сравниваются слои, затем specificity; в одном слое exact producer enable сильнее group disable. Поздний exact enable может снять нижний disable. Exact enable и disable одного producer в одном слое отказывают даже при позднем перекрытии. only_rules задаёт filter и не включает неактивный producer. Пустой итоговый selection, dead exact selector, enable вне своего/нижнего итогового filter и explicit enable при muted option activity отказывают. Высокий disable может намеренно сузить ранний filter. Пустой only_rules убирает нижний filter, но пустые maps никогда не сбрасывают options.

Обычно канал выбирается напрямую. Объявленные роли допускают filter-exempt channels или diagnostics, следующие за выбранным addressed producer. Это не дополнительные включения: explicit disable их producer по-прежнему останавливает его. annotation.unresolved-directive и annotation.unused-directive выбираются напрямую; unsupported/invalid threshold errors следуют за addressed producer. Исправь входное значение вместо сокрытия configuration error посторонним only filter.

bin/qmx rules печатает accepted root/level options отдельно от CLI aliases, затем итоговый only filter и все tied decisive disabled texts. Строка Selection source: ... (...; layer N) берёт реальный origin и layer index. Один writer, повторённый в cells, выводится один раз; одинаковый текст разных слоёв не смешивается. Listing проверяет документ и stated selection, но не effective-band build/conclude и не runtime state. Directive text/JSON сохраняют все decisive disabling texts и исключают снятые поздним enable; JSON selection.disabled остаётся списком строк. Формы значений и слоёв см. в конфигурации.

Окружение прозы

QMX_ASCII проверяется до запуска любой команды. Без учёта регистра 1/true/yes/on включают ASCII; 0/false/no/off, пустое и отсутствующее значение оставляют Unicode. Иное значение даёт отказ с кодом 3 и допустимыми значениями в причине. Структурированный отказ указывает source.kind: environment и source.name: QMX_ASCII.

Режим действует на четыре прозаических формата анализа и всю диагностику ErrorStream, включая прогресс, отчёты в stdout и файлы --output. Заменяется закрытая таблица глифов продукта; другой Unicode, например Café, не меняется. Глиф таблицы внутри имени тоже заменяется: K✓ становится K+. Для сохранения такого имени используй Unicode. Структурированные идентичности не меняются. Stdout других команд — rules, directive text, отдельный debug output и DOT — находится вне этого режима.

Селектор неймспейса использует объявленный неймспейс находки. Для файлового агрегата (annotation.*, duplication.clone) подходит любой неймспейс, открытый в файле или принадлежащий его декларациям. Если нет ни того ни другого, используется глобальный неймспейс. --class не выбирает файловый агрегат. suppress_namespaces намеренно не делает этот файловый шаг: используй suppress_paths. Перекрывающиеся namespace exclusions сохраняют кредит первому совпадению.

suppressed --namespace/--class отказывает с кодом 3: документ composition описывает весь прогон. --show-suppressed допустим; заголовок списка в stderr говорит, что он относится ко всему прогону и селектор к нему не применён. Анализ и итоговый код выхода всегда относятся ко всему прогону.