# Runbook: М7 Фаза 8 — переезд на оборону «роутер-наставник» (активация М1–М6)

**Owner:** владелец репозитория (шаги settings.json / keychain / ENV — только он; Claude'у закрыты)
**Frequency:** один раз (большое переключение) + откат при необходимости
**Last Updated:** 2026-06-09 · **Last Run:** —
**Кодовая фраза эпика:** «роутер-наставник»

> **Что это.** Пошаговая инструкция владельцу: как **включить** новую цельную оборону из 6 «машин» (М1–М6) + две новые двери (G1 verify, Level B criterion) + поглощённую дисциплину, и **уволить** старый «зоопарк» мелких сторожей — атомарно, с тест-гейтом до и откатом после. Код всех машин уже построен (commit-not-push на `worktree-brainrepo`). Эта Фаза 8 — **активация**, не разработка.
>
> **Источники истины:** spec `docs/superpowers/specs/2026-06-08-router-mentor-machine-7-design.md` §8 (ИИ-проводка судьи) / §9 (план переезда) / §10 (список увольнений) + аудит `docs/superpowers/audits/2026-06-09-phase8-readiness-audit.md` (A-блок, GO/NO-GO). При расхождении этого runbook со spec — приоритет у spec.

---

## Purpose

Перевести защиту контроллера со «старого зоопарка» (≈20 разрозненных хуков `router-gate`/`verify-before-push`/`llm-judge-*` и т.д.) на цельный контур М1–М6, где:
- **необратимое** рубит пол М5 (вне зависимости от плана);
- **вне плана** рубит стена М2;
- **приёмку ТЗ/плана/результата** ведёт судья М4;
- **законную дверь** (аварийный выход + правка ЗАКОНА) держит escape М6;
- **видимость** даёт доска «кто на посту» (§7).

Применять **один раз**, когда тест-гейт §9.2 зелёный по каждому пункту. Не применять частично (кроме осознанного поэтапного включения судьи через shadow — см. Шаг 5).

---

## Prerequisites

- [ ] Весь код М7 (G1 + Level B + G2) **смержен в `main`** (Вариант 3 «пуш» выполнен) — Фаза 8 включает то, что в `main`.
- [x] Регрессия tools-only зелёная: **3478 passed / 2 skipped / 0 failed** (обновлено 2026-06-10 после M6 FIX-5 +13; планка §9.2 ≥3350+2skip; исходная spec ≥2843 перекрыта). **Тест-гейт §9.2 верифицирован зелёным 2026-06-10** — per-machine М1–М6 + интеграционные smokes (31 файл / 328 GREEN), все пункты §9.2 покрыты автоматными тестами с fail-CLOSE-ассертами.
- [ ] Доступ к `.claude/settings.json` (правка хуков — **только владелец**, Claude'у закрыт).
- [ ] Доступ к **OS keychain** (Windows Credential Manager через `keytar`) для провижининга двух ключей.
- [ ] Доступ к **пользовательским ENV** (Windows: `rundll32 sysdm.cpl,EditEnvironmentVariables`) для трёх флагов.
- [ ] Ключ модели судьи (`ROUTER_LLM_KEY`) — тот же механизм, что у классификатора/L4 (уже есть в user env по прецеденту L4).
- [ ] Снят актуальный бэкап `.claude/settings.json` (для отката Шаг 7).

---

## Procedure

### Шаг 0: Бэкап settings.json (точка отката)
```
Copy-Item .claude\settings.json .claude\settings.json.bak-phase8-<дата>
```
**Expected result:** копия создана.
**If it fails:** не продолжать — без бэкапа откат §9.4 невозможен.

---

### Шаг 1: Провижининг двух ключей в keychain (НЕ в ENV)

Ключи **только в keychain** (env-fallback вырезан, Δ4 — анти-утечка через логи). Сервисы:

| Назначение | keychain service | account | питает |
|---|---|---|---|
| Ключ подписи расписок | `router-mentor-receipts` | `default` | verify-gate (G1) + criterion-gate (Level B) + М5 подписанный GREEN |
| Ключ судьи (подпись под-прогонов) | `router-mentor-judge` | `default` | судья М4 (дисциплина #1: вердикт без валидного под-прогона не принимается) |

Провижининг (пример через node+keytar — владелец генерит длинный случайный секрет per service):
```
node -e "require('keytar').setPassword('router-mentor-receipts','default', <СЕКРЕТ1>)"
node -e "require('keytar').setPassword('router-mentor-judge','default', <СЕКРЕТ2>)"
```
**Expected result:** оба ключа читаются (`getPasswordSync` возвращает значение).
**If it fails:** без ключа подписи verify/criterion-gate уйдут в `keyMissing` → fail-CLOSE (заблокируют commit/push); без ключа судьи — дисциплина #1 судьи fail-closed. Проверить, что `keytar` установлен и доступен.

> **Примечание про node -e:** на этой машине `node -e` рубит content-floor у Claude (отмычка). Это команда **владельца** в его терминале, не Claude.

---

### Шаг 2: ИИ-проводка судьи М4 (§8 — последняя проводка владельца)

Обёртка `enforce-judge-gate` гейтит расход рубильником, но **реальный llmCall-транспорт** и извлечение «продукта на суд» в `runJudgeGate` владелец подключает на этом шаге (до подключения судья = нейтральный GO даже при mode=block — сессию не кирпичит).

- [ ] Подключить реальный транспорт модели в `runJudgeGate` (паттерн `callAnthropicAPI` из `router-classifier`, модель `CLASSIFIER_MODEL`/Sonnet, ключ `ROUTER_LLM_KEY` в user env).
- [ ] Убедиться, что журнал под-прогонов судьи пишется в неподделываемый канал (М4 §9.1 F1).

**Expected result:** при включённом флаге судья делает реальный вызов (не мок).
**If it fails:** оставить судью в `inert`/`shadow` — оборона М1/М2/М3/М5/М6 работает и без думающего слоя судьи (механический пол М4 + громкий крик).

> **Архитектурный нюанс (урок L4):** регистрировать в settings.json нужно **обёртку** `enforce-judge-gate`, НЕ движок (`judge-orchestrator`/`judge-engine`) — у движка нет рубильника $0.

---

### Шаг 3: Большое переключение — атомарно зарегистрировать 13 хуков (§9.3)

В `.claude/settings.json` добавить **разом** все 13 хуков защитного контура. Форма команды: `node tools/<имя>.mjs`. Матчеры — по заголовку каждого хука (сверка с фикстурой `tools/floor-manifest-check.test.mjs`).

| # | Событие | Хук | Matcher | Роль |
|---|---|---|---|---|
| 1 | PreToolUse | `enforce-floor.mjs` | `*` | М5 пол: вето-до-плана на необратимое + content-floor (Bash/PowerShell) |
| 2 | PreToolUse | `enforce-supreme-gate.mjs` | `*` | М2 стена: default-deny вне запечатанного плана |
| 3 | PreToolUse | `enforce-normative-content-rules.mjs` | `Edit\|Write\|MultiEdit\|NotebookEdit` | М1/М5 защита нормативки/памяти (КАРТА/ЗАКОН) |
| 4 | PreToolUse | `enforce-read-path-deny.mjs` | `Read` | М5 read-exfil (transcript/runtime/secrets) |
| 5 | PreToolUse | `enforce-mcp-classification.mjs` | `mcp__*` | М5 egress-exfil (исходящий MCP-payload) |
| 6 | PreToolUse | `enforce-snapshot.mjs` | `*` | М6 снимок: точка отката перед разрушительным (после пола) |
| 7 | PreToolUse | `enforce-judge-gate.mjs` | `*` (Гейт-2: Write плана + per-tool надзор) | М4 судья (рубильник + режим) |
| 8 | PreToolUse | `enforce-verify-gate.mjs` | `Bash` | G1: подписанный verify-receipt перед commit/push |
| 9 | PreToolUse | `enforce-criterion-gate.mjs` | `Bash` | Level B: по-критерийный mutation-proven GREEN |
| 10 | PreToolUse | `enforce-todowrite-skill-verifier.mjs` | `TodoWrite` | поглощённая дисциплина (журнал-K2) |
| 11 | PostToolUse | `enforce-skill-journaler.mjs` | `Skill` | М1 журналер навыков (неподделываемый канал K2) |
| 12 | PostToolUse | `enforce-floor-escape-consume.mjs` | `*` | М6 escape: one-shot погашение гранта |
| 13 | Stop | `enforce-coverage-verify.mjs` | — | поглощённая дисциплина coverage (журнал-K2) |

**Companion-хуки (оставить/добавить, не входят в 13 «required», но нужны контуру):**
- SessionStart: `floor-manifest-check.mjs` — самопроверка регистрации (доска кричит «ПОСТ ПУСТОЙ», если кто-то из 13 не зарегистрирован).
- доска «кто на посту»: генератор `STATUS.md` (расширен §7) — read-only.
- наблюдение: `observer-stop-hook.mjs`, `cost-stop-hook.mjs`, `askuser-cosmetic-detector` — остаются (§10 «Остаются»).

**Expected result:** все 13 в settings.json; на следующем SessionStart `floor-manifest-check` не кричит (`mode: protected`).
**If it fails (кричит «ПОСТ ПУСТОЙ»):** в WARN перечислены отсутствующие — дописать их. Это сигнал, не блок (Δ8).

---

### Шаг 4: Снять весь зоопарк (§10) — в той же атомарной правке settings.json

> **⚠️ Порядок критичен (V1/V1-PS, DOC-1):** `router-gate`/`powershell-gate` снимать ТОЛЬКО после того, как пол М5 (хук #1) зарегистрирован — иначе ≈20 Bash-классов + весь PowerShell открываются. Регистрация (Шаг 3) и снятие (Шаг 4) — **одна атомарная правка**, не два захода.

Удалить из `.claude/settings.json` регистрации:
- **Старая защита (растворена в пол/стену §5):** `router-gate`, `powershell-gate`, `runtime-write-deny`, `verify-before-push`, `verify-record`, `branch-switch`.
- **Старый судья (L4):** `llm-judge-per-tool`, `llm-judge-response-scan`.
- **Старый роутер-классификатор:** `router-prehook`, `router-tool-gate`, `router-stop-gate`, `router-embedding-warmup` (заменён М3).
- **Поглощённая дисциплина (теперь в М4/М5 журнал-K2):** `memory-coverage`, `coverage-verify`(старая версия), `tdd-gate`, `tdd-real-test-verifier`, `self-debrief-detector`, `rationalization-audit`, `todowrite-skill-verifier`(старая версия), `prompt-injection`(reminder).
- **Мёртвый груз (no-op):** `decomposition-detector`, `safe-baseline-metering`, `parallel-session-lock`.
- **Бессмысленные (субагенты запрещены):** `subagent-return-scanner`, `subagent-prompt-prefix`.

> **NB:** новые журнал-K2 версии `enforce-coverage-verify.mjs` (#13) и `enforce-todowrite-skill-verifier.mjs` (#10) — это НЕ старые одноимённые хуки. Старые снять, новые (из таблицы Шага 3) оставить. Различить по тому, что новые в `DEFAULT_REQUIRED_HOOKS` (G2, манифест 11→13).

**Expected result:** в settings.json остались только 13 + companion-хуки; зоопарка нет.
**If it fails:** см. Откат (Шаг 7).

---

### Шаг 5: Три ENV-флага (рубильники)

Через `rundll32 sysdm.cpl,EditEnvironmentVariables` (user scope), затем **перезапуск Claude Code**:

| ENV | Значение | Эффект |
|---|---|---|
| `ROUTER_MENTOR_VERIFY_ENABLED` | `1` | включает verify-gate (G1) + criterion-gate (Level B). Без флага — inert ($0). |
| `ROUTER_MENTOR_JUDGE_ENABLED` | `1` | включает судью М4. Без флага — inert ($0). |
| `ROUTER_MENTOR_JUDGE_MODE` | `shadow` → позже `block` | shadow: судья логирует, НЕ блокирует (D28 «сперва тихо»); block: блокирует на NO-GO. |

> **Рекомендация дизайнера (§11, не обязательна):** судью сперва в `shadow` на короткий период обкатки, затем `block`. Урок L4: живой судья в первый день может пере-блокировать рабочий цикл. verify/criterion-gate можно сразу включать (они механические, не ИИ).

**Expected result:** после перезапуска — `floor-manifest-check` зелёный; verify/criterion-gate активны; судья в выбранном режиме.
**If it fails:** снять флаг (вернуть в inert) — оборона М1/М2/М3/М5/М6 не зависит от этих флагов.

---

### Шаг 6: shadow → block для судьи (отдельным шагом, после обкатки)

- [ ] Понаблюдать доску §7: режим судьи `shadow`, есть ли ложные NO-GO в логе.
- [ ] Нет ложных блоков → сменить `ROUTER_MENTOR_JUDGE_MODE=block` + перезапуск.

**Expected result:** судья в `live-block`; на доске режим = `live-block`.
**If it fails (судья кирпичит цикл):** вернуть `shadow` (или снять `ROUTER_MENTOR_JUDGE_ENABLED`); пол М5 продолжает рубить необратимое.

---

### Шаг 7 (Откат, §9.4): если переключение глючит
```
Copy-Item .claude\settings.json.bak-phase8-<дата> .claude\settings.json -Force
```
+ при необходимости снять три ENV-флага (вернуть всё в inert) + перезапуск.
**Expected result:** возврат к до-переездному состоянию (зоопарк назад).
**If it fails:** escape/снимок М6 — точки возврата `refs/floor-snapshots/<id>` (создаются `enforce-snapshot` перед разрушительным).

---

## Verification

- [ ] SessionStart `floor-manifest-check` → `mode: protected` (не кричит «ПОСТ ПУСТОЙ»).
- [ ] Доска `STATUS.md` §7: все М1–М6 зарегистрированы + режим судьи показан корректно (inert/shadow/live-block).
- [ ] **Per-machine smokes (§9.2):** каждая М1–М6 блокирует свой класс, fail-CLOSE, громко.
- [ ] **Интеграционные smokes (§9.2):** escape **сквозной** (стена+пол+egress чтут клик владельца); манифест **кричит** при снятом страже; **ЗАКОН** требует ключ, **КАРТА** — нет; дисциплина fail-CLOSE+громко на спровоцированной ошибке; **журнал-факт** не обходится текстом контроллера (Класс 1 закрыт).
- [ ] Зоопарка в settings.json нет; verify/criterion-gate реально блокируют commit без подписанного GREEN.

---

## Troubleshooting

| Symptom | Likely Cause | Fix |
|---|---|---|
| commit/push заблокирован `[verify-gate]`/`[criterion-gate]` сразу после включения | флаг ON, но ключ `router-mentor-receipts` не в keychain → `keyMissing` fail-CLOSE | провижинить ключ (Шаг 1) или снять `ROUTER_MENTOR_VERIFY_ENABLED` |
| Судья блокирует даже безобидное | живой `block` без обкатки (урок L4) | `ROUTER_MENTOR_JUDGE_MODE=shadow` или снять `ROUTER_MENTOR_JUDGE_ENABLED` |
| Доска «ПОСТ ПУСТОЙ» | один из 13 не зарегистрирован | дописать отсутствующий (WARN перечисляет имена) |
| Реальный `force-push`/запись в `.env` проходит несмотря на escape | зоопарк ещё не снят (escape чтут только М2/М5/egress) — DOC-1 | завершить Шаг 4 (снять зоопарк) |
| Bash-команда вида `cp X ~/.claude/runtime/...` не блокируется | пол М5 (хук #1) не зарегистрирован, а `router-gate` уже снят | срочно вернуть порядок: пол ON до снятия router-gate (Шаг 3 до Шага 4) |

---

## Rollback

Полный откат — Шаг 7: восстановить `.claude/settings.json` из бэкапа `.bak-phase8-<дата>` + снять три ENV-флага + перезапуск. Зоопарк возвращается, новые хуки уходят в inert. Снимки М6 (`refs/floor-snapshots/<id>`) — резерв для отката разрушительных действий, исполненных в окно переключения.

---

## Escalation

| Situation | Contact | Method |
|---|---|---|
| Тест-гейт §9.2 красный по любому пункту | — | НЕ переключать; вернуть в подготовку §9.1 |
| Судья кирпичит цикл и shadow не помогает | владелец | снять `ROUTER_MENTOR_JUDGE_ENABLED`, эскалировать в новую сессию «роутер-наставник» |
| Пол/стена блокируют легитимную работу без escape | владелец | escape М6 (AskUser-грант) на конкретное действие; разбор причины отдельно |

---

## History

| Date | Run By | Notes |
|---|---|---|
| 2026-06-09 | Claude (подготовка runbook) | docs-only; код G1+Level B+G2 построен (commit-not-push); активация — шаги владельца |
| 2026-06-10 | Claude (refresh + §9.2) | M6 FIX-5 закрыт (key-gated, commits `7faef3c9..ae3f841c`); D-3 доска live закрыта (`84231a14`); регрессия 3449→**3478**; **тест-гейт §9.2 верифицирован зелёным** (31 файл / 328 GREEN, предусловие C закрыто). Снимок+runbook освежены. |
