stop-ai-slop — гейт против slop-комментариев
Единый источник правды по политике комментариев: таблица правил и детектор живут в scripts/scan.mjs (const RULES). OpenCode comment-gate plugin импортирует детекцию отсюда — править правила надо здесь, а не в плагине.
Политика: комментарий — максимум одна строка и только неочевидное внешнее ограничение, инвариант или воркэраунд. Пересказ диффа живёт в коммите, why теста — в имени теста. Исключение: многострочный JSDoc/docstring для публичного контракта класса/функции (ограничения, инварианты, поведение ошибок); пересказ сигнатуры и чейнджлог внутри него запрещены.
Когда запускать
Перед каждым коммитом. Путь к сканеру — scripts/scan.mjs относительно корня скилла; подставьте свой <SKILL_DIR> (например, ~/.config/opencode/skills/stop-ai-slop):
node <SKILL_DIR>/scripts/scan.mjs --staged
В OpenCode-сессиях write/edit/multiedit дополнительно блокируются на записи плагином comment-gate (error-правила); незнакомые имена инструментов с write-формой payload гейтятся по форме, а неоценённый мутирующий вызов к линтуемому файлу пишется в аудит-лог с вердиктом unevaluated. В Claude Code и вне сессий — через pre-commit hook (--install ниже) или вручную.
Правила
| Правило |
Severity |
Why |
Write |
Ignore-when |
multi-line-comment |
error |
Многострочный комментарий — почти всегда пересказ кода или диффа. Через год его никто не перечитает, а рассинхрон с кодом не заметит никто. |
// сбрасываем здесь, т.к. ниже освобождаем слот |
doc-блок (JSDoc/docstring//// doc-комментарии) с контрактной документацией; короткий 2-строчный why с why-маркером (because/since/чтобы/…); легаси — через baseline |
changelog-marker |
error |
История изменений живёт в гите. «Было/стало» в коде устаревает в момент коммита и дальше только врёт. Одиночное «вместо/было» — обычная проза; сигнал чейнджлога — пара маркеров в одном блоке комментария или сильный маркер (this fixes, must take over, was…, now…, before this change, the old … kept, we used to; ru: «до этого изменения», «старое правило держало»). |
ничего в коде — причину пишем в сообщение коммита |
дословная цитата внешней спеки, где формулировка зафиксирована |
long-comment |
error |
Длинная строка — признак простыни. Ограничение, достойное комментария, формулируется коротко. |
// сбрасываем здесь, т.к. ниже освобождаем слот |
doc-блок; строка с длинной ссылкой на спеку/issue |
vend/step-numbered |
warning |
Нумерация дублирует порядок строк кода. После первой правки шаги вставляются между — номера врут. |
const normalized = normalize(payload) |
протокол из внешнего документа с фиксированной нумерацией шагов |
vend/section-divider |
warning |
Баннеры — признак файла-простыни. Навигацию даёт структура кода, а не линейки. |
ничего — навигацию даёт структура модулей |
сгенерированный файл |
vend/markdown-in-comment |
warning |
Markdown в комментарии — документация, которую никто не читает рядом с кодом; она устаревает. |
// сбрасываем здесь, т.к. ниже освобождаем слот |
docstring, который реально рендерится генератором доков; одиночный |flag| в прозе — строка таблицы требует минимум трёх пайпов |
vend/this-function-opener |
warning |
«This function does X» пересказывает сигнатуру. Ценность только в неочевидном ограничении. |
// дедупликация по id, т.к. источник шлёт повторы |
публичный API с обязательным JSDoc по внешнему требованию |
vend/file-summary-header |
warning |
Оглавление файла устаревает при первой же правке. Структуру видно по символам файла. |
ничего — файл начинается с кода |
лицензионная шапка, требуемая политикой репо |
vend/generic-todo |
warning |
TODO без тикета — вечный долг: некому искать и некогда чинить. |
// TODO KRY-482 снять воркэраунд после фикса upstream |
локальный черновик до первого коммита |
vend/ticket-ref |
warning |
Тикет-ссылка без контекста ротирует вместе с трекером (Jira→GitHub миграции) и протекает чейнджлог в код. Правило неактивно, пока в конфиге не задан ticketPattern. |
// TODO KRY-482: снять воркэраунд после апстрима |
комментарий документирует сам тикет (трекер-агенты, migration notes) |
vend/cross-file-ref |
warning |
Указатель на строку чужого файла гниёт при первой же правке там: номер перестаёт совпадать, и ни один инструмент этого не заметит. URL и host:port не флагаются. |
// формат фиксирован вендором, см. спеку из тикета |
URL с якорем #L12, host:port; требуется разделитель пути или известное кодовое расширение |
vend/obvious-comment |
warning |
Пересказ строки под ним не добавляет информации: код сам себя описывает, а пересказ рассинхронизируется при первом же рефакторинге. Комментарий с «почему» (т.к., чтобы, иначе, must, должен…) не флагается. |
// сбрасываем здесь, т.к. ниже освобождаем слот |
комментарий содержит обоснование; только кодовые профили, не проза |
vend/ai-plan-narration |
warning |
Ссылки на план, ТЗ или промпт и подтверждения «как было запрошено» — метаданные сессии, а не свойство кода: после закрытия задачи референт исчезает, и комментарий превращается в шум. Источник требования — тикет или имя теста. |
// таймаут 30 с, т.к. вендор не отвечает быстрее |
дословная цитата внешней спеки, где формулировка зафиксирована |
vend/ai-vocab-density |
warning |
Плотность канонных ИИ-слов — статистическая сигнатура генерации (Juzek & Ward 2025): где есть одно слово, там обычно есть и другие. Одиночное слово бывает и у человека; три разных в комментариях одного файла — уже сигнатура. |
обычная человеческая лексика |
дословная цитата из внешнего текста, где формулировка зафиксирована |
vend/research-citation |
warning |
Цитата вида (Cormen et al., 2009) или arXiv-id документирует процесс написания кода, а не его свойство: при смене источников ссылка гниёт, и рассинхрона никто не замечает. Коду нужен инвариант, а не библиография. |
инвариант своими словами: // высота дерева <= 2·log(n+1) |
порт алгоритма с формулой из статьи, где ссылка дана в README |
vend/self-suppression |
warning |
Директива в одной правке с кодом, который она глушит, — амнистия без ревизии: никто не проверил обоснование. |
// stop-ai-slop-ignore-next-line vend/step-numbered -- нумерация из внешнего протокола |
full-scan: директива уже в репо, подавление легитимно |
vend/cjk-noise |
warning |
Переключение модели на китайский посреди идентификатора или строки не читается и не компилируется осмысленно; склейка иероглифов с латиницей — маркер невычищенной генерации, а не осознанной i18n-строки. |
const TAB_LABELS = { features: 'Функции' } |
легальные китайские комментарии и строки i18n без смежности с латиницей; prose-файлы (.md/.html/.xml/.rst/.adoc) не проверяются; подавление директивой |
vend/zero-width-chars |
error |
Невидимые символы — канал инъекций и обфускации (Unicode Instruction Injection, Trojan Source): текст выглядит не так, как исполняется. |
const label = 'test' |
нет (всегда артефакт или инъекция) |
vend/bidi-controls |
error |
BiDi-override меняет визуальный порядок кода без изменения логики: ревьюер видит не тот код, что исполняется. Марки U+200E/U+200F порядок не переопределяют, но в коде это артефакт генерации или инъекция; в комментариях и prose-файлах они легальны для RTL-текста, поэтому там не флагуются. |
const url = 'example.com' |
U+200E/U+200F внутри комментария или prose-файла — легальная RTL-типографика |
Error блокирует (exit 1, write-time gate бросает). Warning — учитель: выводится, не блокирует.
Если гейт заблокировал правку
- убрать комментарий или сжать до одной строки WHY, 2) перезаписать правку, 3) легитимный случай — критерий ignore-when правила (
--explain <id>), suppression-директива с причиной или baseline только для легаси; гейт не отключать.
Полное обоснование по правилу: node <SKILL_DIR>/scripts/scan.mjs --explain <rule-id> — выводит Why / Instead of / Write / Ignore-it-when из той же таблицы.
Режимы scan.mjs
scan [paths...] — полное сканирование (160 расширений и 26 имён файлов, таблица в README). В git-репозитории обход = git ls-files --cached --others --exclude-standard: gitignored-мусор (кэши, venv, вендор, бандлы, артефакты сборки) невидим; вне репо — обход каталогов. Сгенерированные файлы эксемптся от slop-правил: суффиксы имён экосистем (*.g.dart, *_pb2.py, *_pb.go, *.min.js, zz_generated.*, …), tool-named шапки первых 10 строк (@generated, Code generated by … DO NOT EDIT, <auto-generated, …) или lax-пара «generat/codegen + do not edit»; голый «DO NOT EDIT» без слова про генерацию не эксемптит. Файлы с NUL в первых 8КБ — бинарные, пропускаются. Нулевые зависимости, Node >= 18, работает на win32, linux и macOS.
--staged — только добавленные строки из git diff --cached -U0. Вне git-репозитория: exit 0 с пометкой.
--baseline-write — перезаписать stop-ai-slop.baseline.txt текущими находками. Baseline — способ закрыть легаси: записи вычитаются из вывода обоих режимов. Формат v2 хранит на находку пару строк relpath:line + fp:<hash> (hash правила и текста находки): сдвиг строк от правок выше не воскрешает легаси, а изменённый текст флагается как новый слоп; v1-файлы (relpath:line, строки с # — комментарии) читаются до следующего --baseline-write.
--baseline-prune — удалить из baseline записи без живых находок; амнистирует удалённое легаси, не трогая новый слоп.
--bench / --bench-write — FP-регрессионная когорта: 8 пин-репозиториев OSS (SHA до 2025-01-01, таблица BENCH_COHORT), счётчики находок по правилам без конфига и baseline; --bench сравнивает с bench-history.json (рост счётчика = регрессия = exit 1), --bench-write перезаписывает эталон. Нужны git и сеть; кэш ~/.cache/stop-ai-slop/bench (переопределяется STOP_AI_SLOP_BENCH_CACHE).
--audit [N] — последние N записей аудит-лога решений write-time плагина (loaded/blocked/passed с файлом и правилами); путь лога — переменная STOP_AI_SLOP_LOG, по умолчанию ~/.config/opencode/logs/comment-gate.jsonl. Плагин загружается на старте сессии OpenCode: после правок плагина нужен рестарт. Шаг 0 диагностики: если в логе нет новых записей после редактирования — процесс OpenCode не подхватил новую версию плагина.
--stdin-path — читает JSON hook-пейлоад из stdin (tool_input.file_path) и сканирует один файл; при срабатывании гейта печатает находки в stderr и выходит с кодом 2, чтобы Claude Code передал их модели (шаблон хука: hooks/hooks.json).
--self-test — саботаж-тест на временных фикстурах; exit != 0 при любом расхождении.
--install — в репозитории: добавить npm scripts stop-ai-slop / stop-ai-slop:all (если есть package.json) и подключить .git/hooks/pre-commit с node .../scan.mjs --staged. Идемпотентно; существующее тело hook не перезаписывает — дописывает блок с маркером.
--install --strict — то же самое, но hook запускает --strict, так что warning тоже блокируют гейт.
--install-hooks — пишет хук-конфиги для Codex CLI, VS Code Copilot и Devin CLI + печатает сниппеты для Gemini CLI/Qwen Code; идемпотентен, чужие хуки не затирает
--install-rules — генерирует rules-файлы из таблицы RULES для Cursor, Windsurf, Aider, Cline, Devin и блок в copilot-instructions; чужой контент без маркера не затирается
--diff <ref> — добавленные строки файлов, отслеживаемых в репо, относительно ref; неотслеживаемые файлы не видны.
--fix [paths...] — применить механические фиксы одним проходом по всей области скана (без агента/LLM): удалить multi-line/шапку-резюме/разделитель/чейнджлог-комментарий, снять префикс «Step N:», вырезать реальные невидимые и BiDi-символы. Затем рескан: выживает то, что чинится только головой (long-comment, this-function-opener, generic-todo, markdown-in-comment, cjk-noise) — они печатаются и дают exit 1 при error. Идемпотентно. Не трогает: escape-форму невидимых символов (предмет кода, BOM-тест), легальный emoji-ZWJ и ведущий BOM, suppression-директивы и подавленные находки, сгенерированные/бинарные/gitignored файлы.
--fix --dry-run — превью: напечатать unified-diff (контекст 2) всех планируемых правок по файлам и итог запланировано N правок в M файлах; не чинится автоматически: K, ничего не записывая, exit 0. Сначала смотреть, потом применять.
--strict — warning тоже блокируют гейт (exit 1).
--format <text|json|sarif> — машиночитаемый вывод вместо текста: json = rdjson (reviewdog), sarif = 2.1.0 (code scanning); exit-коды от формата не зависят, итоговая строка slop-gate: печатается только в text.
- Конфиг
.stop-ai-slop.yaml в корне репо — override severity правил (off/warning/error), maxCommentLength, excludePaths; читается режимами scan/--staged/--diff/--pre-tool, write-time плагин работает с дефолтами.
- Сгенерированный код: эксемпт только от slop-правил — security-правила (
vend/zero-width-chars, vend/bidi-controls, vend/cjk-noise) продолжают флагать (отравленный codegen — supply-chain сигнал). Пользовательские сигналы: .gitattributes с linguist-generated и generatedPaths в конфиге (префиксы как у excludePaths); scanGenerated: true снимает эксемпт. Детали — раздел «Generated code» в README.
--explain <rule-id> — полное обоснование правила (Why / Instead of / Write / Ignore it when).
--mcp — MCP-сервер по stdio (JSON-RPC 2.0): три инструмента slop_scan / slop_explain / slop_baseline; согласование версий протокола 2024-11-05 / 2025-11-25 / 2026-07-28.
--pre-tool — PreToolUse-хук Claude Code: читает stdin JSON {tool_name, tool_input}, сканирует предлагаемый дельта-контент (Write content или Edit new_string минус old_string), при error-находках выводит их в stderr и exit 2 — блокирует запись до исправления. Понимает также write_file/replace (Gemini CLI, Qwen Code), apply_patch с V4A-патчем в tool_input.command (Codex CLI, мультифайл) и неизвестные имена по форме payload (VS Code Copilot, Devin CLI); read-only инструменты не гейтятся.
--help — справка по всем режимам и флагам.
Директивы подавления: // stop-ai-slop-ignore-next-line [rule-id], // stop-ai-slop-ignore-line [rule-id], // stop-ai-slop-ignore-file (после -- — причина). Синтаксис комментариев берётся из профиля языка (160 расширений и 26 имён файлов; см. таблицу профилей в README): # — комментарий в py/sh/yaml, но препроцессор в C и атрибут в Rust; детектор видит inline-комментарии после кода, блоковые комментарии без маркера на средних строках, doc-блоки, UTF-16 с BOM; zero-width символы игнорируются при матчинге.
Вывод
<relpath>:<line> <rule-id> [<severity>] <сообщение>
instead: <что написать вместо>
Коды выхода: 0 — чисто; 1 — сработал гейт (error-находки вне baseline; warnings — при --strict); 2 — ошибка использования или git (неверный флаг, несуществующий ref).
1---2name: stop-ai-slop3description: Comment-slop policy and mechanical gate (scan.mjs, pre-commit install). Use only when the user explicitly asks to check comment policy, scan or deslop comments, install the stop-ai-slop gate, or debug why the gate blocked a commit. Do not load for ordinary code edits, commits or delegated subtasks — comment-gate enforces the rules at write time.4metadata:5 source: https://skillmd.com/skills/whitebite/stop-ai-slop6---78# stop-ai-slop — гейт против slop-комментариев910Единый источник правды по политике комментариев: таблица правил и детектор живут в `scripts/scan.mjs` (const `RULES`). OpenCode comment-gate plugin импортирует детекцию отсюда — править правила надо здесь, а не в плагине.1112Политика: комментарий — максимум одна строка и только неочевидное внешнее ограничение, инвариант или воркэраунд. Пересказ диффа живёт в коммите, why теста — в имени теста. Исключение: многострочный JSDoc/docstring для публичного контракта класса/функции (ограничения, инварианты, поведение ошибок); пересказ сигнатуры и чейнджлог внутри него запрещены.1314## Когда запускать1516Перед каждым коммитом. Путь к сканеру — `scripts/scan.mjs` относительно корня скилла; подставьте свой `<SKILL_DIR>` (например, `~/.config/opencode/skills/stop-ai-slop`):1718```19node <SKILL_DIR>/scripts/scan.mjs --staged20```2122В OpenCode-сессиях write/edit/multiedit дополнительно блокируются на записи плагином comment-gate (error-правила); незнакомые имена инструментов с write-формой payload гейтятся по форме, а неоценённый мутирующий вызов к линтуемому файлу пишется в аудит-лог с вердиктом `unevaluated`. В Claude Code и вне сессий — через pre-commit hook (`--install` ниже) или вручную.2324## Правила2526<!-- stop-ai-slop:rules:start -->27| Правило | Severity | Why | Write | Ignore-when |28| --- | --- | --- | --- | --- |29| `multi-line-comment` | error | Многострочный комментарий — почти всегда пересказ кода или диффа. Через год его никто не перечитает, а рассинхрон с кодом не заметит никто. | // сбрасываем здесь, т.к. ниже освобождаем слот | doc-блок (JSDoc/docstring/`///` doc-комментарии) с контрактной документацией; короткий 2-строчный why с why-маркером (because/since/чтобы/…); легаси — через baseline |30| `changelog-marker` | error | История изменений живёт в гите. «Было/стало» в коде устаревает в момент коммита и дальше только врёт. Одиночное «вместо/было» — обычная проза; сигнал чейнджлога — пара маркеров в одном блоке комментария или сильный маркер (this fixes, must take over, was…, now…, before this change, the old … kept, we used to; ru: «до этого изменения», «старое правило держало»). | ничего в коде — причину пишем в сообщение коммита | дословная цитата внешней спеки, где формулировка зафиксирована |31| `long-comment` | error | Длинная строка — признак простыни. Ограничение, достойное комментария, формулируется коротко. | // сбрасываем здесь, т.к. ниже освобождаем слот | doc-блок; строка с длинной ссылкой на спеку/issue |32| `vend/step-numbered` | warning | Нумерация дублирует порядок строк кода. После первой правки шаги вставляются между — номера врут. | const normalized = normalize(payload) | протокол из внешнего документа с фиксированной нумерацией шагов |33| `vend/section-divider` | warning | Баннеры — признак файла-простыни. Навигацию даёт структура кода, а не линейки. | ничего — навигацию даёт структура модулей | сгенерированный файл |34| `vend/markdown-in-comment` | warning | Markdown в комментарии — документация, которую никто не читает рядом с кодом; она устаревает. | // сбрасываем здесь, т.к. ниже освобождаем слот | docstring, который реально рендерится генератором доков; одиночный `\|flag\|` в прозе — строка таблицы требует минимум трёх пайпов |35| `vend/this-function-opener` | warning | «This function does X» пересказывает сигнатуру. Ценность только в неочевидном ограничении. | // дедупликация по id, т.к. источник шлёт повторы | публичный API с обязательным JSDoc по внешнему требованию |36| `vend/file-summary-header` | warning | Оглавление файла устаревает при первой же правке. Структуру видно по символам файла. | ничего — файл начинается с кода | лицензионная шапка, требуемая политикой репо |37| `vend/generic-todo` | warning | TODO без тикета — вечный долг: некому искать и некогда чинить. | // TODO KRY-482 снять воркэраунд после фикса upstream | локальный черновик до первого коммита |38| `vend/ticket-ref` | warning | Тикет-ссылка без контекста ротирует вместе с трекером (Jira→GitHub миграции) и протекает чейнджлог в код. Правило неактивно, пока в конфиге не задан ticketPattern. | // TODO KRY-482: снять воркэраунд после апстрима | комментарий документирует сам тикет (трекер-агенты, migration notes) |39| `vend/cross-file-ref` | warning | Указатель на строку чужого файла гниёт при первой же правке там: номер перестаёт совпадать, и ни один инструмент этого не заметит. URL и host:port не флагаются. | // формат фиксирован вендором, см. спеку из тикета | URL с якорем #L12, host:port; требуется разделитель пути или известное кодовое расширение |40| `vend/obvious-comment` | warning | Пересказ строки под ним не добавляет информации: код сам себя описывает, а пересказ рассинхронизируется при первом же рефакторинге. Комментарий с «почему» (т.к., чтобы, иначе, must, должен…) не флагается. | // сбрасываем здесь, т.к. ниже освобождаем слот | комментарий содержит обоснование; только кодовые профили, не проза |41| `vend/ai-plan-narration` | warning | Ссылки на план, ТЗ или промпт и подтверждения «как было запрошено» — метаданные сессии, а не свойство кода: после закрытия задачи референт исчезает, и комментарий превращается в шум. Источник требования — тикет или имя теста. | // таймаут 30 с, т.к. вендор не отвечает быстрее | дословная цитата внешней спеки, где формулировка зафиксирована |42| `vend/ai-vocab-density` | warning | Плотность канонных ИИ-слов — статистическая сигнатура генерации (Juzek & Ward 2025): где есть одно слово, там обычно есть и другие. Одиночное слово бывает и у человека; три разных в комментариях одного файла — уже сигнатура. | обычная человеческая лексика | дословная цитата из внешнего текста, где формулировка зафиксирована |43| `vend/research-citation` | warning | Цитата вида (Cormen et al., 2009) или arXiv-id документирует процесс написания кода, а не его свойство: при смене источников ссылка гниёт, и рассинхрона никто не замечает. Коду нужен инвариант, а не библиография. | инвариант своими словами: // высота дерева <= 2·log(n+1) | порт алгоритма с формулой из статьи, где ссылка дана в README |44| `vend/self-suppression` | warning | Директива в одной правке с кодом, который она глушит, — амнистия без ревизии: никто не проверил обоснование. | // stop-ai-slop-ignore-next-line vend/step-numbered -- нумерация из внешнего протокола | full-scan: директива уже в репо, подавление легитимно |45| `vend/cjk-noise` | warning | Переключение модели на китайский посреди идентификатора или строки не читается и не компилируется осмысленно; склейка иероглифов с латиницей — маркер невычищенной генерации, а не осознанной i18n-строки. | const TAB_LABELS = { features: 'Функции' } | легальные китайские комментарии и строки i18n без смежности с латиницей; prose-файлы (.md/.html/.xml/.rst/.adoc) не проверяются; подавление директивой |46| `vend/zero-width-chars` | error | Невидимые символы — канал инъекций и обфускации (Unicode Instruction Injection, Trojan Source): текст выглядит не так, как исполняется. | const label = 'test' | нет (всегда артефакт или инъекция) |47| `vend/bidi-controls` | error | BiDi-override меняет визуальный порядок кода без изменения логики: ревьюер видит не тот код, что исполняется. Марки U+200E/U+200F порядок не переопределяют, но в коде это артефакт генерации или инъекция; в комментариях и prose-файлах они легальны для RTL-текста, поэтому там не флагуются. | const url = 'example.com' | U+200E/U+200F внутри комментария или prose-файла — легальная RTL-типографика |48<!-- stop-ai-slop:rules:end -->4950Error блокирует (exit 1, write-time gate бросает). Warning — учитель: выводится, не блокирует.5152## Если гейт заблокировал правку53541) убрать комментарий или сжать до одной строки WHY, 2) перезаписать правку, 3) легитимный случай — критерий ignore-when правила (`--explain <id>`), suppression-директива с причиной или baseline только для легаси; гейт не отключать.5556Полное обоснование по правилу: `node <SKILL_DIR>/scripts/scan.mjs --explain <rule-id>` — выводит Why / Instead of / Write / Ignore-it-when из той же таблицы.5758## Режимы scan.mjs5960- `scan [paths...]` — полное сканирование (160 расширений и 26 имён файлов, таблица в README). В git-репозитории обход = `git ls-files --cached --others --exclude-standard`: gitignored-мусор (кэши, venv, вендор, бандлы, артефакты сборки) невидим; вне репо — обход каталогов. Сгенерированные файлы эксемптся от slop-правил: суффиксы имён экосистем (`*.g.dart`, `*_pb2.py`, `*_pb.go`, `*.min.js`, `zz_generated.*`, …), tool-named шапки первых 10 строк (`@generated`, `Code generated by … DO NOT EDIT`, `<auto-generated`, …) или lax-пара «generat/codegen + do not edit»; голый «DO NOT EDIT» без слова про генерацию не эксемптит. Файлы с NUL в первых 8КБ — бинарные, пропускаются. Нулевые зависимости, Node >= 18, работает на win32, linux и macOS.61- `--staged` — только добавленные строки из `git diff --cached -U0`. Вне git-репозитория: exit 0 с пометкой.62- `--baseline-write` — перезаписать `stop-ai-slop.baseline.txt` текущими находками. Baseline — способ закрыть легаси: записи вычитаются из вывода обоих режимов. Формат v2 хранит на находку пару строк `relpath:line` + `fp:<hash>` (hash правила и текста находки): сдвиг строк от правок выше не воскрешает легаси, а изменённый текст флагается как новый слоп; v1-файлы (`relpath:line`, строки с `#` — комментарии) читаются до следующего `--baseline-write`.63- `--baseline-prune` — удалить из baseline записи без живых находок; амнистирует удалённое легаси, не трогая новый слоп.64- `--bench` / `--bench-write` — FP-регрессионная когорта: 8 пин-репозиториев OSS (SHA до 2025-01-01, таблица `BENCH_COHORT`), счётчики находок по правилам без конфига и baseline; `--bench` сравнивает с `bench-history.json` (рост счётчика = регрессия = exit 1), `--bench-write` перезаписывает эталон. Нужны git и сеть; кэш `~/.cache/stop-ai-slop/bench` (переопределяется `STOP_AI_SLOP_BENCH_CACHE`).65- `--audit [N]` — последние N записей аудит-лога решений write-time плагина (`loaded`/`blocked`/passed с файлом и правилами); путь лога — переменная `STOP_AI_SLOP_LOG`, по умолчанию `~/.config/opencode/logs/comment-gate.jsonl`. Плагин загружается на старте сессии OpenCode: после правок плагина нужен рестарт. Шаг 0 диагностики: если в логе нет новых записей после редактирования — процесс OpenCode не подхватил новую версию плагина.66- `--stdin-path` — читает JSON hook-пейлоад из stdin (`tool_input.file_path`) и сканирует один файл; при срабатывании гейта печатает находки в stderr и выходит с кодом 2, чтобы Claude Code передал их модели (шаблон хука: `hooks/hooks.json`).67- `--self-test` — саботаж-тест на временных фикстурах; exit != 0 при любом расхождении.68- `--install` — в репозитории: добавить npm scripts `stop-ai-slop` / `stop-ai-slop:all` (если есть package.json) и подключить `.git/hooks/pre-commit` с `node .../scan.mjs --staged`. Идемпотентно; существующее тело hook не перезаписывает — дописывает блок с маркером.69- `--install --strict` — то же самое, но hook запускает `--strict`, так что warning тоже блокируют гейт.70- `--install-hooks` — пишет хук-конфиги для Codex CLI, VS Code Copilot и Devin CLI + печатает сниппеты для Gemini CLI/Qwen Code; идемпотентен, чужие хуки не затирает71- `--install-rules` — генерирует rules-файлы из таблицы RULES для Cursor, Windsurf, Aider, Cline, Devin и блок в copilot-instructions; чужой контент без маркера не затирается72- `--diff <ref>` — добавленные строки файлов, отслеживаемых в репо, относительно ref; неотслеживаемые файлы не видны.73- `--fix [paths...]` — применить механические фиксы одним проходом по всей области скана (без агента/LLM): удалить multi-line/шапку-резюме/разделитель/чейнджлог-комментарий, снять префикс «Step N:», вырезать реальные невидимые и BiDi-символы. Затем рескан: выживает то, что чинится только головой (`long-comment`, `this-function-opener`, `generic-todo`, `markdown-in-comment`, `cjk-noise`) — они печатаются и дают exit 1 при error. Идемпотентно. Не трогает: escape-форму невидимых символов (предмет кода, BOM-тест), легальный emoji-ZWJ и ведущий BOM, suppression-директивы и подавленные находки, сгенерированные/бинарные/gitignored файлы.74- `--fix --dry-run` — превью: напечатать unified-diff (контекст 2) всех планируемых правок по файлам и итог `запланировано N правок в M файлах; не чинится автоматически: K`, ничего не записывая, exit 0. Сначала смотреть, потом применять.75- `--strict` — warning тоже блокируют гейт (exit 1).76- `--format <text|json|sarif>` — машиночитаемый вывод вместо текста: json = rdjson (reviewdog), sarif = 2.1.0 (code scanning); exit-коды от формата не зависят, итоговая строка `slop-gate:` печатается только в text.77- Конфиг `.stop-ai-slop.yaml` в корне репо — override severity правил (`off`/`warning`/`error`), `maxCommentLength`, `excludePaths`; читается режимами scan/--staged/--diff/--pre-tool, write-time плагин работает с дефолтами.78- Сгенерированный код: эксемпт только от slop-правил — security-правила (`vend/zero-width-chars`, `vend/bidi-controls`, `vend/cjk-noise`) продолжают флагать (отравленный codegen — supply-chain сигнал). Пользовательские сигналы: `.gitattributes` с `linguist-generated` и `generatedPaths` в конфиге (префиксы как у excludePaths); `scanGenerated: true` снимает эксемпт. Детали — раздел «Generated code» в README.79- `--explain <rule-id>` — полное обоснование правила (Why / Instead of / Write / Ignore it when).80- `--mcp` — MCP-сервер по stdio (JSON-RPC 2.0): три инструмента `slop_scan` / `slop_explain` / `slop_baseline`; согласование версий протокола `2024-11-05` / `2025-11-25` / `2026-07-28`.81- `--pre-tool` — PreToolUse-хук Claude Code: читает stdin JSON `{tool_name, tool_input}`, сканирует предлагаемый дельта-контент (`Write` content или `Edit` new_string минус old_string), при error-находках выводит их в stderr и exit 2 — блокирует запись до исправления. Понимает также `write_file`/`replace` (Gemini CLI, Qwen Code), `apply_patch` с V4A-патчем в `tool_input.command` (Codex CLI, мультифайл) и неизвестные имена по форме payload (VS Code Copilot, Devin CLI); read-only инструменты не гейтятся.82- `--help` — справка по всем режимам и флагам.8384Директивы подавления: `// stop-ai-slop-ignore-next-line [rule-id]`, `// stop-ai-slop-ignore-line [rule-id]`, `// stop-ai-slop-ignore-file` (после `--` — причина). Синтаксис комментариев берётся из профиля языка (160 расширений и 26 имён файлов; см. таблицу профилей в README): `#` — комментарий в py/sh/yaml, но препроцессор в C и атрибут в Rust; детектор видит inline-комментарии после кода, блоковые комментарии без маркера на средних строках, doc-блоки, UTF-16 с BOM; zero-width символы игнорируются при матчинге.8586## Вывод8788```89<relpath>:<line> <rule-id> [<severity>] <сообщение>90 instead: <что написать вместо>91```9293Коды выхода: 0 — чисто; 1 — сработал гейт (error-находки вне baseline; warnings — при `--strict`); 2 — ошибка использования или git (неверный флаг, несуществующий ref).