# Router-gate re-scope: «боевое блокируем, локальную разработку разрешаем»

**Дата:** 2026-06-02
**Статус:** design (утверждён владельцем; реализация — отдельным планом)
**Автор контекста:** сессия lead-region-tails

## Проблема

Router-gate v4 (`tools/enforce-router-gate.mjs`) работает в режиме «по умолчанию запрещено»
(whitelist для Bash + hard-blacklist + MCP-классификатор + дисциплинарные хуки). Он задумывался
как защита **боевого** контура (выкат на liderra.ru, изменение боевой БД, секреты, запуск
воркфлоу), но по факту блокирует и **весь локальный инструмент разработки**: `composer install`,
`npm install`, `git worktree`, `git commit`/`push`, и даже правку тест-файлов (через
`enforce-tdd-real-test-verifier`). Это делает обычную разработку через контроллера непрактичной —
любая PHP/JS-задача с тестами упирается в стену (подтверждено в сессии 2026-06-02: попытка сделать
fix реестра Россвязи провалилась на цепочке взаимно-охраняющих замков).

## Цель

Перенастроить замок так, чтобы он блокировал **только боевое и опасное**, а **локальную
разработку разрешал** — сохранив при этом дисциплину работы контроллера и защиту боевого контура.

## Решения (утверждены владельцем 2026-06-02)

1. **Дисциплину оставляем.** Хуки качества (TDD-gate, tdd-real-test-verifier, chain-recommendation,
   graph-first, override-limit, llm-judge, coverage-verify, memory-coverage и пр.) — **не трогаем**.
   Контроллер продолжает писать тесты до кода и не срезать углы.
2. **Защиту боевого оставляем железно.** Выкат/боевая БД/секреты/запуск воркфлоу/защищённые
   пути — без изменений.
3. **Инструменты разработки разрешаем.** composer/npm/pest/git/worktree.
4. **Граница git:** ветки — контроллер сам (commit/push в не-главную ветку + подготовка PR);
   слияние в main, push в main, force-push, выкат — **клик владельца**.

## Подход

**Approach A (выбран):** точечно расширить whitelist дев-инструментами, сохранив философию
«по умолчанию запрещено». Правим **два файла** — `tools/enforce-router-gate.mjs` (composer/npm) и
`tools/shell-content-rules.mjs` (git; там общий `classifyGitCommand`). MCP-классификатор
(`tools/mcp-tool-classifier.mjs`) и дисциплинарные хуки — без изменений.

Отвергнут **Approach B** (перевернуть в default-allow + blacklist опасного): любой пропуск в
перечне опасного = дыра; ломает безопасную философию default-deny.

## Матрица: что блокируем / что разрешаем

### Остаётся ЗАБЛОКИРОВАННЫМ

| Категория | Примеры | Где |
|---|---|---|
| Боевой контур | выкат на сайт, изменение боевой БД, секреты/`.env`, защищённые пути (CLAUDE.md, memory/, transcripts, `~/.claude/runtime`) | без изменений |
| GitHub на запись | `create_*`/`update_*`/`merge_*`/`push_files`/`actions_run_trigger` | MCP-классификатор без изменений (read-only, открытый 2026-06-02, остаётся) |
| Опасные команды | `rm`/`mv`/`cp`/`chmod`/`chown`, `curl -X POST/PUT/DELETE`, `wget`, `nc`/`ncat`/`socat`, `node -e` с `fs.*`, `eval`, `bash -c`/`sh -c`, `python -c`, redirects в protected | hard-blacklist без изменений |
| Дисциплина | TDD-gate, tdd-real-test-verifier, override-limit, chain-recommendation, graph-first, llm-judge, coverage | хуки без изменений |
| Главная ветка | `git push` в main, `git push --force`, слияние в main | новый «страж main» |

### Становится РАЗРЕШЁННЫМ (локальная разработка)

| Инструмент | Команды |
|---|---|
| Composer | `composer install`, `composer dump-autoload`, `composer require`, `composer update` |
| NPM | `npm install`, `npm ci`, `npm run <script>` |
| Тесты | `pest`, `vendor/bin/pest`, `php artisan test` (уже частично в whitelist) |
| Git (ветки) | `git commit`, `git add`, `git branch`, `git switch`/`checkout`, `git worktree`, `git stash`, `git push` **в не-главную ветку** |

## Изменения в коде (два файла)

Git-логика живёт не в самом router-gate, а в общем модуле `shell-content-rules.mjs`
(`classifyGitCommand`, используется и Bash-, и PowerShell-гейтом). Поэтому правок — два файла.

### `tools/enforce-router-gate.mjs` (composer / npm)

1. **Из hard-blacklist (`BASH_HARD_BLACKLIST`) убрать** строки про `composer install/update/require/remove`
   и `npm install/i/update/remove/uninstall`. `yarn`/`pnpm` остаются заблокированными (проект на npm,
   не нужны). Истинно-опасные fs/сеть/exec (`rm/mv/cp/chmod`, `curl POST`, `wget`, `nc`, `node -e fs`,
   `eval`, `bash -c`, `python -c`, redirects) — **без изменений**.
2. **В whitelist (`SAFE_EXACT`) добавить:** `composer (install|update|require|remove|dump-autoload|dump)`,
   `npm (install|i|ci)`, `npm run <script>` (любой скрипт). Существующие `composer show/outdated/test/...`
   и `npm test/run test/run lint` — остаются.

### `tools/shell-content-rules.mjs` (git)

1. **Новый `GIT_DEV_SUB`** = `{add, commit, branch, switch, checkout, stash, worktree}` → в
   `classifyGitCommand` после hard-pattern-проверки возвращать `allow`. Эти подкоманды **убрать** из
   `GIT_CONDITIONAL_SUB`. (`worktree` сейчас падает в default-deny — попадёт в dev-allow.)
2. **`GIT_HARD_PATTERNS` не трогаем** — `--no-verify`, `git add -f`, `git -c`, force-push, `--output`/`-o`
   и т.п. по-прежнему блокируются ПЕРВЫМИ, до dev-allow. То есть `git commit --no-verify` и `git add -f`
   остаются заблокированы даже как «dev».
3. **Страж main для `push`** (`mainPushGuard`, чистая функция): `push` остаётся, но —
   если в аргументах фигурирует `main`/`master` как ref (`git push origin main`, `HEAD:main`, `:main`)
   → **block** (клик владельца); force-push уже заблокирован `GIT_HARD_PATTERNS`. Иначе (`git push origin <feature>`,
   bare `git push`) → allow. Допущение: bare `git push` считаем пушем не-главной ветки (контроллер по модели
   всегда на не-главной ветке); пуш в main возможен только явным `origin main` → пойман.
4. **Conditional остаётся** для `merge, rebase, reset, cherry-pick, revert, pull, clean` (require approval) —
   риск потери работы / слияние в main = клик владельца.

**Не меняем:** `tools/mcp-tool-classifier.mjs`, `tools/bash-tokenizer.mjs` (`isMutatingSegment` — чейн-правило
C13 «цепочка с мутацией → блок» сохраняется), любые `enforce-*` дисциплинарные хуки, `.claude/settings.json`.

## Тестирование (TDD)

Через `tools/enforce-router-gate.test.mjs` (vitest, работает в основной копии):

- `composer install` / `composer require x` → allow; `composer` (без подкоманды) → как раньше.
- `npm install` → allow; `npm run build` → allow.
- `git commit -m x` / `git worktree add ...` / `git push origin feature-x` → allow.
- `git push origin main` / `git push --force` → **block** (страж main).
- Регресс: опасное по-прежнему блокируется — `rm -rf x`, `curl -X POST`, `node -e "...fs..."`,
  `eval`, `python -c` → block.
- Полная регрессия tools-тестов (`npx vitest run --root app --config vitest.config.tools.mjs`).

## Граница реализации (bootstrap-нюанс)

Сам этот re-scope — bootstrap-исключение: его нельзя делать в worktree (worktree пока заблокирован).
Реализуется в основной копии (там активен живой замок и работает vitest). После правки замка
`git`/`worktree`/`composer` становятся разрешены — дальнейшие задачи (например, fix реестра)
пойдут уже по модели «ветка + PR».

## Остаточные риски (приняты)

- Разрешён `composer require`/`npm install` → теоретический supply-chain (установка пакета).
  Принято: это собственный проект владельца; дисциплина и code-review остаются.
- `rm`/`mv`/`cp` остаются заблокированы — если реально мешают разработке, пересматриваем отдельно
  (файловые правки покрываются инструментами Write/Edit).
- «Страж main» опирается на парсинг аргументов `git push`; экзотические формы (push по URL,
  refspec-трюки) при сомнении → block (fail-safe в сторону защиты main).

## Что НЕ входит (YAGNI)

- Не инвертируем модель замка (default-deny остаётся).
- Не трогаем боевые воркфлоу, секреты, MCP-write.
- Не ослабляем дисциплину.
