Ревью кода
> Проверяйте изменения кода на корректность, безопасность, производительность и качество с помощью команды /review.
Быстрый старт
# Проверить локальные незакоммиченные изменения
/review
# Проверить pull request (по номеру или URL)
/review 123
/review https://github.com/org/repo/pull/123
# Проверить и оставить inline-комментарии в PR
/review 123 --comment
# Проверить локальные изменения и применить находки к рабочему дереву
/review --fix
# Проверить конкретный файл
/review src/utils/auth.ts
# Быстрая непроверенная проходка (без субагентов)
/review --effort low
/review 123 --effort mediumЕсли незакоммиченных изменений нет, /review сообщит об этом и остановится — агенты не запускаются.
Уровни детализации
--effort low|medium|high — trade-off между глубиной и скоростью:
| Уровень | Что выполняется | Лимит находок | Вердикт | Публикация в PR |
|---|---|---|---|---|
low | 3-6 направленных inline-проходов по диффу (масштабируется по размеру диффа) плюс gap sweep — без субагентов, без сборки/тестов, без правил проекта | 10 (непроверенных) | Нет | Никогда |
medium | Полный пайплайн high без самых затратных проходов: параллельный fan-out finder’ов по сокращённому набору измерений, плюс сборка/тесты и один проход проверки | Без лимита (проверенных) | Approve ограничен до Comment | Никогда |
high | Полный пайплайн: 14 параллельных агентов → шардированная проверка → итеративный обратный аудит | Без лимита (проверенных) | Approve / Request changes / Comment | С --comment |
По умолчанию: high для ревью PR, medium для локальных ревью и ревью файлов. Использование --comment принудительно устанавливает high (опубликованные комментарии должны пройти проверку) — для цели не-PR --comment игнорируется с предупреждением и не меняет уровень детализации. Medium сохраняет агентов безопасности и покрытия тестами, а также сборку/тесты, но убирает состязательные персоны, diff-специализированные finder’ы и обратный аудит — поэтому тонкая Critical, которую обнаружит только второй проход, может проскочить; используйте --effort high для security-чувствительных или предрелизных ревью. Только low является непроверенным. Изоляция worktree применяется к ревью PR в том же репозитории; кросс-репозиторные PR работают в облегчённом режиме (только diff, без worktree и сборки/тестов). Проход low помечен как непроверенный, не выдаёт вердикт и никогда не записывает инкрементальный кэш ревью, поэтому последующий запуск --effort high никогда не будет пропущен как «уже проверено»; medium проверен, но его Approve ограничен до Comment, потому что никто не смотрел дважды на то, что первый проход пропустил. Механика получения диффа идентична на всех уровнях — ревью PR всегда используют изолированный worktree и то же разрешение базы, поэтому ревью никогда не идёт против неправильной базы. Одно различие в области остаётся: инкрементальный кэш — только для high, поэтому повторное ревью high может покрыть только новые коммиты (lastCommitSha..HEAD), тогда как low/medium всегда ревьюят полный diff PR.
Как это работает
Команда /review запускает многоэтапный пайплайн:
Шаг 1: Определение области + уровня детализации (локальный diff / worktree PR / файл)
Захват diff в файл + разбиение на чанки
Шаг 2: Загрузка правил ревью проекта (medium/high)
Шаг 3C: low effort: 3-6 inline-проходов + gap sweep [0 вызовов субагентов]
Шаг 3A: high, <=500 src И <=3200 всего: 14 агентов [14+ вызовов LLM]
|-- Агент 0: Issue Fidelity и присвоение корневой причины
|-- Агент 1a: Корректность — построчный скан
| (вкл. проверку языковых ловушек + маршрутизации wrapper'ов)
|-- Агент 1b: Корректность — аудит удалённого поведения
|-- Агент 1c: Корректность — кросс-файловый трассировщик
|-- Агент 2: Безопасность
|-- Агент 3a: Переиспользование и дублирование
|-- Агент 3b: Уровень абстракции
|-- Агент 3c: Согласованность и ясность
|-- Агент 4: Производительность и эффективность
|-- Агент 5: Покрытие тестами
|-- Агент 6: Свободный аудит (3 персоны: 6a/6b/6c)
|-- Агент 8: Diff-специализированные finder'ы (0-2, только когда
| домен диффа их требует)
'-- Агент 7: Сборка и тесты (запускает shell-команды)
Шаг 3B: high, >500 src ИЛИ >3200 всего: территория × измерение [N+5..7+3H вызовов]
(N чанков, 5-7 агентов по всему диффу, 3 инвариантных
агента на каждый тяжёлый файл H)
|-- 1 агент на чанк (~400 строк диффа, все измерения,
| только его территория, возвращает квитанцию покрытия)
|-- 3 инвариантных агента на каждый сильно переписанный
| исходный файл (весь файл; state/timers, counters/
| returns/errors, config/early-returns)
|-- Агент 0: Issue Fidelity (весь diff)
|-- Агент 7: Сборка и тесты (весь репозиторий)
|-- Агент 1b: Удалённое поведение (весь diff —
| кросс-чанковая половина; чанки хранят локальную)
|-- Агент 1c: Кросс-файловый трассировщик (весь diff)
|-- Агент 8: Специализированные finder'ы (весь diff, 0-2)
'-- Матрица покрытия тестами (весь diff)
Шаг 4: Дедупликация --> Шардированная проверка (<=8 находок на агента)
--> Агрегация [ceil(F/8) вызовов, F=находки]
Шаг 5: Итеративный обратный аудит, fan-out по чанкам;
остановка после 2 последовательных сухих раундов (лимит 10/5/3 по топологии)
Шаг 6: Предоставление результатов + вердикт (high; при low: только находки)
Каноникализация находок -> .qwen/tmp/...-findings.json
Шаг 6B: Применение находок + запись результатов по каждой находке (только --fix)
Шаг 7: Отправка ревью PR (inline-комментарии, если запрошено; только high)
Шаг 8: Сохранение отчёта + инкрементальный кэш (кэш: только high)
Шаг 9: Очистка (удаление worktree + временных файлов)Шаги 3A/3B/4/5 — это пайплайн high-effort; при --effort low|medium единый inline-проход (Шаг 3C) заменяет их.
Агенты ревью
| Агент | Фокус |
|---|---|
| Агент 0: Issue Fidelity | Доказательства из связанного issue, присвоение корневой причины и проверка того, решает ли PR заявленную проблему |
| Агент 1a: Построчный скан | Проходит каждый hunk вместе с окружающей функцией: неправильные условия, off-by-one, пропущенный await, языковые ловушки, маршрутизация wrapper/proxy |
| Агент 1b: Аудит удалённого поведения | Проходит каждую удалённую/заменённую строку: называет инвариант, который она обеспечивала, и ищет, где новый код его восстанавливает — включая удалённые экспорты, чья замена часто живёт в другом файле и тихо меняет значение по умолчанию. В 3B работает по всему диффу (чанк-агенты хранят локальную половину) |
| Агент 1c: Кросс-файловый трассировщик | Проходит всех вызывающих каждого изменённого символа (направление потребителя) и все сайты чтения каждого добавленного поля (направление производителя), а также изменения callee в том же PR |
| Агент 2: Безопасность | Инъекции, XSS, SSRF, обход аутентификации, утечка конфиденциальных данных |
| Агент 3a: Переиспользование и дублирование | Уже ли есть это в кодовой базе? Ищет поведение через grep, называет существующий helper для использования вместо нового, и помечает мёртвый код, оставленный диффом |
| Агент 3b: Уровень абстракции | На правильной ли глубине исправление — или это пластырь на общей инфраструктуре, компенсация downstream для бага upstream, или абстракция для одного вызова? |
| Агент 3c: Согласованность и ясность | Согласованность между соседями (guard, который есть у одного члена параллельного семейства, но отсутствует у другого), дрейф соглашений со ссылкой на локальный пример, вводящие в заблуждение имена/комментарии, излишняя сложность |
| Агент 4: Производительность и эффективность | N+1 запросы, утечки памяти, лишние ре-рендеры, размер бандла |
| Агент 5: Покрытие тестами | Непокрытые тестами пути кода в диффе, отсутствующее покрытие ветвлений, слабые ассерты |
| Агент 6: Свободный аудит | 3 параллельные персоны (атакующий / дежурный в 3 часа ночи / мейнтейнер) — выявляет междисциплинарные проблемы |
| Агент 7: Сборка и тесты | Запускает команды сборки и тестов, сообщает о сбоях |
| Агент 8: Diff-специализированные finder’ы | 0-2 дополнительных finder’а, создаваемых для каждого ревью, когда diff концентрируется в домене с известными режимами отказов (логика переподключения, загрузчики модулей, планировщики, кодеки) |
Три агента корректности являются процедурными: каждый определяется тем, как он проходит diff (построчно / удалённые строки / кросс-файловые рёбра), а не таксономией багов — поэтому их покрытие комплементарно, а не пересекается. Тот же подход разделяет качество кода на три (3a/3b/3c): один агент с чек-листом из шести пунктов на сильно переписанном файле выполняет один пункт; один агент с чек-листом из восьми пунктов нашёл 1 из 5 дефектов, а та же модель, разделённая на три части, нашла все 5 — поэтому чек-лист качества разрезан там, где вопросы действительно различаются. Все агенты работают параллельно (Агент 1 запускает 3 процедурных варианта, Агент 3 запускает 3 среза чек-листа, а Агент 6 запускает 3 варианта персон параллельно, в сумме 14 параллельных задач для ревью PR в том же репозитории, плюс 0-2 finder’ов Агента 8, когда домен диффа их требует — итого 14-16 на практике; Агент 0 пропускается для ревью локального diff и путей к файлам, где запускается 13-15; облегчённый кросс-репозиторный режим также пропускает Агентов 1c и 7, запуская 12-14).
Каждая находка должна описывать сценарий отказа — конкретный вход, состояние или тайминг, который её запускает, и неправильный результат (для находок по качеству — конкретные затраты). Находка, которая не может назвать свой сценарий, отбрасывается у источника, а проверка перетрассирует заявленный сценарий через реальный код, а не оценивает текст находки.
Когда PR содержит более 500 строк изменений исходного кода — или более 3 200 строк диффа в целом, после которых каждый из одиннадцати читающих diff целиком оказывается слишком распылён для внимательного чтения (это ограничение внимания, а не обещание меньшего числа вызовов — тяжёлые файлы и специализированные finder’ы могут сделать 3B дороже) — этот fan-out по измерениям заменяется на fan-out территория × измерение: diff разбивается на чанки по ~400 строк — границы падают на границы hunk’ов, а hunk, слишком большой для одного чанка, разделяется только по объявлению верхнего уровня, никогда внутри функции — и каждый чанк получает собственного агента, который применяет все измерения ревью только к этому чанку.
Гейт намеренно считает строки исходного кода, а не строки диффа. Тестовый код, проза и lockfile доминируют в размере диффа — по последним 40 смержённым PR этого репозитория медианный diff на 41% состоит из тестов — поэтому гейт по сырому размеру разбил бы 173 строки продакшн-кода на территории только потому, что к ним приложено 489 строк новых тестов, оставив этот продакшн-код с одним ревьюером вместо десяти линз (агентов чтения диффа — двенадцать минус Issue Fidelity и Сборка и тесты). Разбиение на чанки в любом случае покрывает каждую строку, включая тесты; гейт решает, сколько ревьюеров и что каждый из них делает. Десять линз чтения диффа, идущих по одному большому диффу, читают одни и те же ранние hunk’и десять раз; один агент на чанк означает, что у каждой строки диффа есть ровно один ответственный ревьюер. Каждый агент чанка возвращает квитанцию Covered:, и чанк без квитанции пересматривается до продолжения — поэтому «блокеров нет» никогда не будет сообщено о коде, который никто не читал.
Исходный файл, который значительно переписан (существующий файл 300+ строк, теперь на 40%+ новый, или имеет 800+ изменённых строк), также получает три инвариантных агента по всему файлу. Тестовые и сгенерированные файлы никогда не квалифицируются — чек-лист спрашивает о полях, таймерах и таксономии ошибок, чего нет в переписанном тестовом файле. Его баги обычно не внутри одного hunk’а, а между новыми строками — таймер, установленный в начале файла, и путь teardown’а на две тысячи строк ниже. Каждый агент читает весь пост-изменённый файл и проходит два-три пункта фиксированного чек-листа: изменяемые поля, очищаемые на каждом пути выхода, таймеры, отменяемые при каждом закрытии (и отмена не отбрасывает захваченные данные), вставки в map, сопоставленные удалениями, счётчики retry, инкрементируемые на каждом входе, возвращаемые значения статуса, которые действительно проверяются, коды ошибок, исчерпывающе классифицированные как постоянные/временные, поля конфигурации, учитываемые на каждом пути, и ранние return’ы, пропускающие необходимый побочный эффект.
Чек-лист намеренно разделён на три части. Один агент со всеми восемью проверками над файлом в 2 400 строк выполнит одну из них правильно; три агента с двумя-тремя проверками каждый выполнят все. Агенты чанков не заменяют это — на PR #6457 каждый из этих дефектов был внутри их назначенной территории, и ни один не был обнаружен. Им не хватало не строк, а вопроса.
Находки проверяются шардированными батчами (не более 8 находок на агента проверки, все запускаются одновременно). Проверщик может отклонить Critical только процитировав код, который ему противоречит (или когда собственные комментарии диффа документируют помеченное поведение как намеренное); всё менее определённое понижается до низкой уверенности, а не удаляется — молча отклонённая Critical невидима для всех последующих этапов, тогда как пониженная всё ещё доходит до человека. После проверки итеративный обратный аудит ищет пробелы, fan-out по одному аудитору на чанк за раунд, каждый с накопительным списком находок. Цикл останавливается после двух последовательных сухих раундов (или лимита раундов плана — сообщается как таковой, а не как сходимость). Лимит зависит от топологии диффа: 10 для небольшого диффа, где раунд — один аудитор; 5 для чанкового, где это один аудитор на чанк; и 3 для огромного диффа (≥ 3000 эффективных строк), когда у запуска есть дедлайн, потому что пять ~90-минутных раундов не помещаются в шестичасовой потолок CI, а ревью, прерванное на полпути, ничего не публикует — без дедлайна огромный diff сохраняет чанковый лимит 5. Оператор может снизить применимый лимит для каждого ревью с помощью настройки review.reverseAuditRounds; повысить его нельзя. Один сухой раунд — не доказательство сходимости, и находки обратного аудита проверяются как любые другие.
Уровни критичности
| Критичность | Значение | Публикуется как комментарий в PR? |
|---|---|---|
| Критично | Обязательно к исправлению перед мержем (баги, безопасность, потеря данных, падение сборки) | Да (только с высокой достоверностью) |
| Рекомендация | Рекомендуемое улучшение | Да (только с высокой достоверностью) |
| Желательно | Опциональная оптимизация | Нет (только в терминале) |
Результаты с низкой достоверностью отображаются в отдельной секции “Needs Human Review” в терминале и никогда не публикуются как комментарии в PR.
Изоляция worktree
При ревью PR команда /review создает временный git worktree (.qwen/tmp/review-pr-<number>) вместо переключения текущей ветки. Это означает:
- Ваше рабочее дерево, проиндексированные изменения и текущая ветка никогда не затрагиваются
- Зависимости устанавливаются в worktree (npm ci и т.д.), чтобы сборка/тесты работали
- Команды сборки и тестов запускаются изолированно, не засоряя локальный кэш сборки
- Если что-то пойдет не так, ваша среда не пострадает — просто удалите worktree
- Worktree автоматически очищается после завершения ревью
- Если ревью прервано (Ctrl+C, сбой), следующая команда /review для того же PR автоматически очистит устаревший worktree перед началом работы. Если прерванная сессия всё ещё оставляет свою аренду — жёсткое завершение, пропускающее это, или многипромптовое ревью, прерванное на более позднем промпте — /review отказывается и называет файл аренды для удаления. Чистые остановки освобождают её: завершённое ревью и ранние остановки (пустой diff, нет новых изменений с момента последнего ревью) все запускают cleanup, который освобождает аренду
- Worktree арендован своей сессии: повторный /review для PR, который уже находится на ревью, отказывается запускаться (называя владельца), а не разбирает worktree работающего ревью
- Отчеты о ревью и кэш сохраняются в основную директорию проекта (не в worktree)
Ревью PR из другого репозитория
Вы можете делать ревью PR из других репозиториев, передав полный URL:
/review https://github.com/other-org/other-repo/pull/456Это выполняется в облегчённом режиме — без worktree, без сборки/тестов. Ревью основано только на тексте diff (полученном через GitHub API). Комментарии в PR все еще могут быть опубликованы, если у вас есть доступ на запись.
| Возможность | В том же репо | Из другого репо |
|---|---|---|
| Ревью LLM (Агенты 0, 1a, 1b, 2-6 + проверка + итеративный обратный аудит) | ✅ | ✅ |
| Агент 1c: Кросс-файловый трассировщик | ✅ | ❌ (нет локальной кодовой базы для grep) |
| Агент 7: Сборка и тесты | ✅ | ❌ (нет локальной кодовой базы) |
| Агент 8: Diff-специализированные finder’ы (0-2, когда домен требует) | ✅ | ✅ (нужен только diff) |
| Inline-комментарии в PR | ✅ | ✅ (если есть доступ на запись) |
| Инкрементальный кэш ревью | ✅ | ❌ |
Inline-комментарии в PR
Используйте --comment, чтобы публиковать находки прямо в PR:
/review 123 --commentИли, после запуска /review 123, введите post comments, чтобы опубликовать находки без повторного запуска ревью.
Что публикуется:
- Находки уровня Critical и Suggestion с высокой достоверностью в виде inline-комментариев к конкретным строкам, каждая с префиксом **[Critical]** или **[Suggestion]**, чтобы блокеры отличались от рекомендаций
- Когда исправление — это одно локализованное изменение, блок ```suggestion, который можно применить одним кликом
- Для вердиктов Approve/Request changes: сводка ревью с вердиктом
- Для вердикта Comment, когда все inline-комментарии опубликованы: отдельная сводка не выводится (inline-комментариев достаточно)
- Сноска об авторстве модели и версии CLI в каждом комментарии (например, — qwen3-coder via Qwen Code /review (v0.21.2)); установите review.attribution в false в вашем пользовательском или системном settings.json (рабочий .qwen/settings.json игнорируется для настроек review.*), чтобы публиковать без неё
Что остается только в терминале:
- Находки уровня Nice to have - Находки с низкой достоверностью
Собственные PR: GitHub не позволяет отправлять ревью с APPROVE или REQUEST_CHANGES на ваши собственные pull request — оба варианта завершаются ошибкой HTTP 422. Когда /review обнаруживает, что автор PR совпадает с текущим аутентифицированным пользователем, он автоматически понижает событие API до COMMENT независимо от вердикта, чтобы отправка прошла успешно. В терминале при этом отображается честный вердикт (“Approve” / “Request changes” / “Comment”) — нейтрализуется только событие ревью на стороне GitHub. Сами находки по-прежнему появляются в виде inline-комментариев к конкретным строкам, поэтому содержательная обратная связь не меняется.
Повторное ревью PR с предыдущими комментариями Qwen Code: когда /review запускается для PR, в котором уже есть предыдущие комментарии ревью Qwen Code, он классифицирует их перед публикацией новых. Только перекрытие на одной строке (существующий комментарий на той же (path, line), что и новая находка) требует подтверждения — это тот случай, когда вы увидите визуальный дубликат на одной и той же строке кода. Комментарии из старых коммитов, комментарии с ответами (считаются решенными) и комментарии, которые просто не пересекаются ни с одной новой находкой, молча пропускаются, с записью в логе терминала, чтобы вы знали, что было отфильтровано.
Проверка статуса CI / сборки перед APPROVE: если вердикт — “Approve”, /review запрашивает check-runs и commit statuses PR перед отправкой. Если какая-либо проверка упала (или все проверки еще в ожидании), событие API автоматически понижается с APPROVE до COMMENT, а тело ревью объясняет причину. Обоснование: ревью LLM читает код статически и не может увидеть ошибки тестов во время выполнения; одобрение при красном CI было бы вводящим в заблуждение. Inline-находки при этом публикуются без изменений. Если вы все равно хотите одобрить (например, при известном нестабильном падении CI), отправьте одобрение GitHub вручную после проверки.
Применение находок (--fix)
--fix — это зеркальное отражение --comment. --comment пишет в pull request, поэтому ему нужен PR; --fix пишет в рабочее дерево, поэтому ему нужно дерево, которое переживёт ревью:
/review --fix # локальные незакоммиченные изменения
/review src/auth.ts --fix # один файлДля PR-цели он игнорируется с предупреждением — ревью PR работает в эфемерном worktree, который удаляется после завершения ревью, поэтому «исправленные» правки там будут отброшены через несколько минут. Вместо этого используйте --comment для публикации находок.
Эффективный --fix устанавливает минимум effort в medium, потому что он редактирует ваши файлы, а low не запускает проверку: применение непроверенной находки — та же ошибка, что и её публикация, только направленная в ваше рабочее дерево, а не в чей-то PR. Он не принуждает к high — находки medium проверены, а обратный аудит, который добавляет high, ищет пропущенные находки, что не относится к решению о применении.
После ревью каждая находка применяется инструментом edit и затем учитывается одним из трёх способов:
| Результат | Значение | Остаётся на вас? |
|---|---|---|
fixed | Правка в вашем дереве | Нет |
skipped | Реальная, не применена — причина сообщается вместе | Да |
no_change_needed | Находка была ошибочной, или код уже обрабатывал это | Нет |
Находка пропускается, когда её исправление изменило бы предполагаемое поведение, потребовало бы изменений далеко за пределами проверяемого диффа, или при повторном рассмотрении оказывается ложным срабатыванием.
Каждая находка получает результат, и это обеспечивается, а не запрашивается. Реестр проходит через qwen review findings --outcomes, который отказывается принимать набор, не покрывающий все — фиксер, который применяет шесть из девяти находок и сообщает о шести, не солгал ни об одной из них, он молча сократил список, и у вас не было бы способа увидеть три, которые выпали.
Находки как данные
Подтверждённые находки каноникализируются в .qwen/tmp/qwen-review-<target>-findings.json до того, как что-либо их потребляет — терминальный отчёт, сохранённый Markdown-отчёт и JSON ревью PR все читают этот единственный артефакт вместо повторного формирования списка. Каждая находка несёт уникальный id (по чему соединяются результаты и resolved-якоря), severity, confidence, source, summary, shortSummary ограниченный 60 символами для рендеринга списков, failureScenario и один или несколько locations — находка с агрегацией по паттерну сохраняет одну локацию на каждое вхождение, поэтому каждая получает свой inline-комментарий.
Прежде всего, ревью проверяет, что оно запускает ваш код. Каждый шаг qwen review … запускает собранный бандл, а не рабочее дерево, поэтому команда ревью, отредактированная с момента последней сборки, не вступит в силу, и запуск будет измерять старое поведение. Сборка записывает дайджест источников ревью, которые она упаковала; parse-args выводит его заново и сравнивает, а drive проверяет ещё раз, потому что бриф верификатора направляет агентов прямо туда, минуя шаг 1. При несовпадении он сообщает в stderr, что бандл не был собран из этих источников, и что нужно пересобрать. Проверка запускается, когда CLI разрешается в собранный dist/cli.js (бинарник qwen или node dist/cli.js); лаунчеры, запускающие несобранный код, такие как npm start и npm run dev, пропускают её. Два случая, когда сравнение невозможно, обрабатываются по-разному: для чекаута, чья сборка предшествует записи, сообщается, что проверка не могла быть выполнена и почему, а установленный пакет — у которого нет источников для сравнения — остаётся без сообщения. Дайджест покрывает команды ревью, файл, который их регистрирует, аренду только для ревью, которую они импортируют извне своей директории, и встроенный навык ревью; он не следует за общими помощниками, которые они импортируют, поэтому тихий запуск означает, что код ревью соответствует бандлу, а не что всё дерево в целом.
Critical, которая уже падала на базовом дереве, откладывается, а не регистрируется. Когда команда тестов упала и base слияния может быть собран, test-delta записывает, какие падающие файлы также падают без pull request. Каноникализация читает это измерение обратно (qwen review findings --test-delta, рядом с --outcomes): Critical, чей собственный текст называет один из этих файлов, понижается до Suggestion, сохраняет свои доказательства, получает измерение, которое её понизило, и поле heldByMeasurement, и понижение объявляется. Тест, который уже был красным, — это не тест, который pull request делает красным — и если он теперь падает по новой причине, укажите какой тест, процитируйте обе стороны и зарегистрируйте её снова как Critical: находка, которая уже несёт измерение и всё равно повышена, остаётся там, где вы её оставили.
Команда валидирует при записи: дублирующийся id, находка без сценария отказа, пустой массив locations или неизвестная severity — это ошибка, а не молча искажённая запись.
Изображения-доказательства в комментариях PR
API GitHub не позволяет прикреплять изображения к комментариям ревью, поэтому /review может хостить изображения-доказательства (скриншоты TUI, рендеринги diff) во внешнем репозитории и ссылаться на них из комментариев. Установите переменную окружения, чтобы включить это:
export QWEN_REVIEW_ASSETS_REPO=your-org/your-repo # репозиторий, в который вы можете пушить
/review 123 --commentМейнтейнеры обычно направляют её на репозиторий, который ревьюится; остальные могут использовать форк или служебный репозиторий. Изображения попадают в ветку pr-assets/<pr>-review с контентно-хешированными именами, и комментарии ссылаются на них по зафиксированному коммитом URL — неизменному, даже если ветка позже сдвинется, и работающему без изменений на GitHub Enterprise.
Для ревью, запускаемых по триггеру GitHub (workflow ревью PR), та же переменная подключается из переменной репозитория с тем же именем: без установленной переменной workflow передаёт пустое значение и публикация отклоняется — ничего не меняется. Мейнтейнер, установивший QWEN_REVIEW_ASSETS_REPO в Actions-переменных репозитория (обычно на сам репозиторий), включает возможность комментариев ревью встраивать PNG-снимки; ветки, которые он записывает, очищаются workflow очистки визуальных материалов, когда переменная указывает на тот же репозиторий, а форк или служебный получатель управляет своим собственным хранением.
Публикация ограничена точно так же, как и постинг: нет назначенного репозитория — нет публикации, а неавторизованный запуск (без эффективного --comment) отклоняется так же, как submit отклоняет. Принимаются только типы изображений (SVG исключён намеренно), с ограничениями по размеру, и байты каждого файла должны соответствовать формату, который заявляет его расширение — неправильно помеченный или неопознанный контент отклоняется. Манифест записывает каждый запушенный файл. Без назначения находки хранят свои доказательства как локальные пути к файлам в терминале и сохранённом отчёте — ничего не ломается, комментарии просто остаются текстовыми.
Последующие действия
После ревью контекстные подсказки появляются в виде ghost text. Нажмите Tab, чтобы принять:
| Состояние после ревью | Подсказка | Что происходит |
|---|---|---|
Локальное ревью, --fix не передан | fix these issues | LLM интерактивно исправляет каждую находку |
| Ревью PR с находками | post comments | Публикует inline-комментарии в PR (без повторного ревью) |
| Ревью PR, ноль находок | post comments | Одобряет PR на GitHub (LGTM) |
| Локальное ревью, все чисто | commit | Коммитит ваши изменения |
Примечание: fix these issues доступно только для локальных ревью, по той же причине, что и --fix — для ревью PR worktree очищается после завершения, поэтому интерактивное исправление после ревью невозможно; используйте --comment или post comments для публикации находок. Когда --fix был передан, находки уже содержат результаты и подсказка исправления не предлагается.
Правила ревью проекта
Вы можете настроить критерии ревью для каждого проекта. /review читает правила из следующих файлов (по порядку):
1. .qwen/review-rules.md (нативный для Qwen Code)
2. .github/copilot-instructions.md (приоритетный) или copilot-instructions.md (резервный — загружается только один из них, не оба)
3. AGENTS.md — секция ## Code Review
4. QWEN.md — секция ## Code Review
Правила внедряются в агентов ревью LLM (0-6) как дополнительные критерии. Для ревью PR правила читаются из базовой ветки, чтобы предотвратить внедрение правил обхода злонамеренным PR.
Контекст репозитория
Репозитории могут передать ревьюерам ограниченные, специфичные для репозитория рекомендации, закоммитив строгий JSON-манифест в .qwen/review-context.json. При effort уровне medium или high /review читает манифест после захвата плана и прикрепляет подходящие рекомендации перед запуском любого агента:
{
"version": 1,
"label": "Example repository",
"rules": [
{
"paths": ["packages/*/src/**"],
"domains": ["runtime"],
"relatedPaths": ["packages/runtime/src/**"],
"recommendedTests": ["npm run test:runtime"],
"requiredConfigurations": ["debug"],
"requiredAgents": ["test-matrix"],
"unverifiedDimensions": ["Alternate runtime was not exercised"],
"verificationNotes": ["Use the repository native test runner"]
}
]
}Правило применяется, когда любой изменённый файл совпадает с одним из его glob-шаблонов paths (*, ? и сегменты **; с учётом регистра). Все совпадающие правила объединяют свои рекомендации: домены и связанные файлы для агентов ревью, рекомендуемые тесты и требуемые конфигурации для агента сборки и тестов, дополнительные роли ревьюеров (учитываются только когда выбранный effort уровень и топология их запускают), и границы доказательств, которые итоговое ревью раскрывает как непроверенные измерения. Массивы могут быть записаны в любом порядке; дубликаты записей отклоняются.
Для ревью PR манифест читается из base-коммита слияния, поэтому ревьюимый PR не может самостоятельно включить или исключить себя из рекомендаций; локальные ревью читают его из текущего worktree. Ревью с низким effort уровнем и кросс-репозиторные ревью пропускают контекст репозитория. Полный контракт и модель доверия описаны в документе дизайна.
Issue Fidelity
Для PR с исправлениями багов агент Issue Fidelity получает доказательства из issue напрямую, а не полагается на текст описания PR. Он запускает подкоманду qwen review issue-context <pr> --repo <owner/repo> --out <file>, которая определяет надежные метаданные GitHub о закрывающих issue и затем получает заголовок, body (оригинальное воспроизведение от репортера) и полную ветку комментариев каждого упомянутого issue — каждое из собственного репозитория issue (PR может закрывать issue в другом репозитории). Этот агент запускается только для целей PR; ревью локального diff и путей к файлам его пропускают.
Множество закрывающих issue — это подсказка для поиска, а не доказательство того, что автор связал правильный issue: если оно пусто, но PR ссылается на очевидное целевое issue, агент всё равно получает его после оценки релевантности (повторный запуск с --issue <n>; простое число разрешается в репозитории PR, тогда как --issue <owner>/<repo>#<n> загружает кросс-репозиторную ссылку из её собственного репозитория). Полученный текст issue рассматривается как ненадежные данные (факты извлекаются, встроенные инструкции игнорируются). Для релевантных issue оригинальное воспроизведение, наблюдаемые данные, ожидаемое поведение и комментарии мейнтейнеров рассматриваются как доказательства наивысшего приоритета для определения того, решает ли PR правильную проблему.
Если доказательства из issue показывают, что вышестоящий сервис или провайдер вернул некорректные данные вне клиентского контракта, изменения клиентского парсера или санитайзера не рассматриваются как валидное исправление корневой причины, если только мейнтейнер явно не запросил защитное обходное решение. Тест, который воспроизводит некорректный вывод вышестоящего сервиса, доказывает лишь то, что обходное решение обрабатывает такую форму данных; он не доказывает, что обходное решение архитектурно уместно.
Пример .qwen/review-rules.md:
# Правила ревью
- Все API-эндпоинты должны проверять аутентификацию
- Запросы к базе данных должны использовать параметризованные выражения
- React-компоненты не должны использовать инлайн-стили
- Сообщения об ошибках не должны раскрывать внутренние путиИнкрементальное ревью
При повторном ревью ранее проверенного PR команда /review проверяет только изменения с момента последнего ревью:
# Первое ревью — полная проверка, создается кэш
/review 123
# PR обновлен новыми коммитами — проверяются только новые изменения
/review 123Кросс-модельное ревью
Если вы смените модель (через /model) и повторно проверите тот же PR, /review обнаружит изменение модели и выполнит полную проверку вместо пропуска:
# Ревью с моделью A
/review 123
# Смена модели
/model
# Повторное ревью — полная проверка моделью B (не пропускается)
/review 123
# → "Предыдущее ревью использовало qwen3-coder. Запускается полная проверка с помощью gpt-4o для получения второго мнения."Кэш хранится в .qwen/review-cache/ и отслеживает как SHA коммита, так и ID модели. Убедитесь, что эта директория добавлена в .gitignore (также подойдет более общее правило, например .qwen/*). Если закешированный коммит был удален при rebase, инструмент вернется к полной проверке. Только ревью high-effort обращаются к кэшу или записывают его — быстрый проход --effort low|medium никогда не считается «уже проверенным».
Отчеты о ревью
Для ревью в рамках одного репозитория результаты сохраняются в виде Markdown-файла в директории .qwen/reviews/ вашего проекта (облегченные кросс-репозиторные ревью пропускают сохранение отчетов):
.qwen/reviews/2026-04-06-143022-pr-123.md
.qwen/reviews/2026-04-06-150510-local.mdОтчеты включают: временную метку, статистику диффа, результаты сборки/тестов, все найденные проблемы со статусом проверки и итоговый вердикт. Заголовки секций и описательный текст следуют языковым настройкам вывода; технические идентификаторы (SHA, пути к файлам, имена гейтов, id находок) остаются без изменений.
Ревью уровня medium и high также сохраняют структурированный JSON-компаньон с тем же именем (например, 2026-04-06-143022-pr-123.json), содержащий канонические находки и составленный вердикт как данные. Web Shell Qwen Code рендерит этот документ как интерактивное представление ревью с фильтруемыми находками; Markdown-отчёт остаётся читаемым человеком архивом.
Детерминированные части пайплайна — разбор аргументов (qwen review parse-args) и решение о событии/теле (qwen review compose-review) — это тестированные подкоманды, а не текст промпта, поэтому грамматика --effort, принуждение --comment, ограничения вердикта и поведение понижения закреплены модульными тестами и не могут разойтись с моделью.
GitHub Enterprise: ревью PR по URL на хосте, отличном от github.com, направляет все вызовы GitHub на этот хост — подкоманды ревью (match-remote, meta, fetch-pr, pr-context, comment-status, issue-context, fetch-diff, comment-body, plan-diff, test-plan, presubmit, compose-review, submit, publish-assets) принимают --host и устанавливают его в коде, поэтому забытый хост не может молча перенаправить ревью на github.com.
Каждый запуск завершается одной машиночитаемой строкой (Review complete: <target> — <disposition>), поэтому скрипты и CI-обёртки могут определить завершение и результат одним совпадением ^Review complete: .
Headless-запуски (qwen review run)
/review — интерактивный. Когда скрипту или CI-задаче нужно запустить ревью и действовать по его результату, используйте headless-обёртку:
qwen review run [target] [--json] [--fail-on request-changes] [--comment] [--quiet]target — это номер PR, URL PR или путь к файлу; пропустите для ревью локального рабочего дерева. Команда запускает CLI этой сборки неинтерактивно (с закрытым stdin, чтобы обнаружение slash-команд работало), направляет прогресс дочернего процесса в stderr и выводит вердикт в stdout — или, с --json, полный объект результата. Вердикт читается из артефакта, который записывает compose-review (тот же JSON, который навык считает авторитетом вердикта), а не разбирается из прозы модели.
Код выхода — это контракт, который должен читать гейт:
| Выход | Значение |
|---|---|
0 | Ревью завершено (независимо от решения) |
1 | Вердикт не достигнут — дочерний процесс упал, истёк таймаут или не оставил составленного артефакта |
3 | Завершено с REQUEST_CHANGES и --fail-on request-changes был установлен (опциональное блокирование) |
3 (не 2) позволяет гейту различать «ревью блокирует» и «инструмент сломался» — yargs уже использует 1 для ошибок использования — без разбора вывода. --timeout-minutes (по умолчанию 120, минимум 1) завершает зависшее ревью и выходит с 1, а отмена команды (Ctrl+C / SIGTERM) завершает группу процессов ревью, а не оставляет их сиротами.
Запуск с ограничением по времени также может экспортировать мягкий дедлайн, чтобы ревью остановило свой цикл обратного аудита с неограниченным временем, пока ещё есть время на проверку, составление и публикацию: QWEN_REVIEW_DEADLINE_EPOCH — момент в Unix-секундах, когда запуск будет убит, а QWEN_REVIEW_DEADLINE_RESERVE_SECONDS (по умолчанию 3600; 0 сохраняет только оценку раунда) — хвост, который должен остаться для проверки последнего раунда, compose-review и отправки. Когда оставшийся бюджет не вмещает ещё один раунд плюс этот хвост, конструктор раундов отказывается его строить, и составленный вердикт раскрывает усечённый аудит (иначе-Approve вердикт ограничен до Comment). Отсутствующий или неправильный дедлайн оставляет ревью без ограничения — внешний таймаут всё ещё ограничивает запуск.
Внутри этого резерва вложен меньший compose floor, QWEN_REVIEW_DEADLINE_COMPOSE_FLOOR_SECONDS (по умолчанию 1200; 0 полностью отключает этот гейт, в любой момент, включая время после дедлайна). Резерв — это одно число, покрывающее «проверить последний раунд плюс составить плюс отправить», что подходит для обычной повторной трассировки по каждой находке, но не для ревью безопасности, чья проверка повторно запускает реальные нагрузки файловой системы/git без ограничений. Поэтому гейт по этому полу стоит на верификаторе, а не на конструкторе раундов: когда остаётся пол или меньше, agent-prompt --role verify отказывается строить (строка VERIFY BUDGET:, выход 4), найденные находки сохраняют метку непроверенных (что ограничивает вердикт), и запускаются compose-review и отправка. Пол строго ниже резерва, поэтому здоровый запуск сначала достигает гейта обратного аудита и никогда до него не доходит; это покрытие для того спана, который резерв не может ограничить.
Анализ влияния между файлами
Специализированный кросс-файловый трассировщик (Агент 1c) выполняет этот проход от начала до конца. Когда изменения кода затрагивают экспортируемые функции, классы или интерфейсы, он ищет всех вызывающих и проверяет совместимость:
- Изменения количества или типов параметров - Изменения типа возвращаемого значения - Удаленные или переименованные публичные методы - Критические изменения API
Он также проходит направление производителя: каждое поле, опция или опциональный параметр, добавленный диффом, трассируется к его сайтам чтения — включая файлы, которые diff не затрагивает. Активный путь кода, читающий поле, которое ничего не заполняет, означает, что функция, которую оно управляет, молча ничего не делает, и это помечается как Critical в сайте чтения.
Для больших диффов (>10 изменённых символов) анализ в направлении вызывающих отдаёт приоритет функциям с изменёнными сигнатурами; направление производителя никогда не ограничивается бюджетом, потому что неизменённая сигнатура — это именно его точка.
Бюджет ревью
Эластичные по размеру диффа части пайплайна масштабируются от него, и масштабирование записывается в план диффа, чтобы каждый этап читал одно число, а не принимал решение самостоятельно:
| Поле бюджета | Что ограничивает | Как масштабируется |
|---|---|---|
inlineAngles | Сколько low-проходов запускается (Шаг 3C) | 3, плюс один на 60 строк исходного кода, максимум 6 существующих углов |
sweep | Запускается ли gap sweep для low | Выключен ниже 25 строк исходного кода |
specialistCap | Потолок Агента 8 | 0 ниже 80 строк исходного кода, иначе 2 |
verifyShard | Находок на агента проверки | Фиксировано 8 — свойство проверщика, а не диффа |
Две вещи, которые он намеренно не делает. Он никогда не убирает измерение целиком: каких агентов должно быть ревью, определяется ростером, который читает уровень детализации, поэтому маленький diff всё равно получает проход по безопасности и покрытию тестами. И он читает строки исходного кода, не строки диффа — 40 строк продакшн-изменений с 900 строками новых тестов — это маленькое изменение, и та же логика уже управляет гейтом territory-fan-out.
Почему полы именно такие: на исправлении опечатки в девять строк шесть inline-проходов — это пять проходов над ничем, а sweep — свежий читатель, ищущий то, до чего первый проход не добрался — нечего искать, когда первый проход добрался до всего. Пол Агента 8 — содержательный: «один домен доминирует в диффе» — это суждение, и суждение, сделанное о сорока строках, каждый раз находит доминирующий домен, потому что сорок строк — это обычно одна вещь.
Эффективность использования токенов
Пайплайн high-effort ограничивает каждый этап (размер шарда, раунды аудита), но общие вызовы масштабируются с находками — ceil(F/8) шардов проверки — и, при 3B, с количеством чанков (обратный аудит работает по чанкам за раунд). Типичный профиль 3A:
| Этап | Вызовы LLM | Примечания |
|---|---|---|
| Агенты ревью (Шаг 3) | 14 (+0-2) | Работают параллельно; кросс-репо пропускает Агентов 1c и 7 (12), локальные/файловые пропускают Агента 0 (13) |
| Шардированная проверка (Шаг 4) | ceil(F/8) | F = находки; не более 8 на агента проверки, запускаются вместе |
| Итеративный обратный аудит (Шаг 5) | 2-10 (3A); раунды × чанки (3B) | Два последовательных сухих раунда для остановки; лимит зависит от топологии — 10 для небольшого диффа, 5 для чанкового, 3 для огромного при наличии дедлайна. 3B делает fan-out по одному аудитору на чанк за раунд |
| Всего | ~17-28 (~15-27) | 3A в том же репо: ~17-28 (типично ~17-19); кросс-репо или локальные/файловые: ~15-27; 3B масштабируется с чанками (см. DESIGN.md) |
Большинство PR сходятся к нижней границе диапазона; лимиты предотвращают неконтролируемый рост затрат в патологических случаях. При --effort low ревью выполняется полностью inline — 0 вызовов субагентов — проходя diff по одному разу на угол вместо одного раза в целом.
Что НЕ помечается
Ревью намеренно исключает:
- Уже существующие проблемы в неизмененном коде (фокус только на диффе) - Стиль или форматирование, которые автоматически нормализуются форматтером, или именование, соответствующее соглашениям вашей кодовой базы — но НЕ существенные проблемы, которые отметил бы линтер или проверка типов (неиспользуемые переменные, недостижимый код, ошибки типов), так как они входят в область проверки - Субъективные предложения “рассмотрите возможность сделать X” без указания на реальную проблему - Незначительный рефакторинг, который не исправляет баг или не снижает риск - Отсутствие документации, если только логика не является по-настоящему запутанной - Проблемы, уже обсуждавшиеся в существующих комментариях к PR (чтобы не дублировать отзывы людей)
Философия дизайна
> Тишина лучше шума. Каждый комментарий должен оправдывать время, затраченное на его чтение.
- Если нет уверенности, является ли что-то проблемой → не сообщайте об этом - Каждая находка называет конкретный сценарий отказа (триггер → неправильный результат) или конкретные затраты — находка, которая не может этого, отбрасывается до того, как дойдёт до вас - Одинаковый паттерн в N файлах → агрегируется в одну находку - Комментарии к PR содержат только находки с высокой степенью уверенности (и только из ревью high-effort, проверенных) - Косметические правки стиля/форматирования, соответствующие соглашениям кодовой базы, исключаются