# LLM-first router overhaul — spec v2.3

**Дата:** 2026-05-24 (v1.0) / 2026-05-25 (v2.0 — переписана целиком) / 2026-05-25 (v2.1 — 16 правок после code review) / 2026-05-25 (v2.2 — закрыты 16 находок 0%-аудита) / 2026-05-25 (v2.3 — +§4.9 coverage announcement).
**Эпик:** пересборка маршрутизации мозга — переход с regex-первичного классификатора + §12 hard-rule на LLM-first классификатор Sonnet 4.6 (с prompt enrichment памяткой) + §17 universal skill-coverage rule + Reviewer как полноценный Claude Code subagent + inheritance для коротких follow-up prompt'ов + автоматический evidence loop для последующей дистилляции эмпирических regex-правил.
**История версий:** v1.0 → v2.0 → v2.1 → v2.2. v1.0 — 8 фактических ошибок. v2.0 — переписана с реальным state inventory. v2.1 — 3 решения после v2.0 + 5 edge cases + 8 мелких = 16 правок. v2.2 — закрыты 16 находок 0%-аудита (1 критическое §17-text↔logic + 6 внутренних несогласованностей + 5 underspecified + 4 typo/ellipsis); полный список — §22.
**Реализация:** 3 implementation-фазы за один эпик (~3.5-4.5 недели), затем ~5-6 месяцев passive evidence collection, затем 4-я фаза distillation (~2-3 недели) через ~6 месяцев.

---

## 0. Карта документа

| § | Тема |
|---|---|
| 1 | Назначение и контекст |
| 2 | Принципы (с явными accepted trade-offs) |
| 3 | Архитектура — общая картина (8 слоёв) |
| 4 | Компоненты по слоям (детально) |
| 5 | Schema эпизода v4.* (поэтапные bumps) |
| 6 | §17 — формальное определение |
| 7 | Что меняется в нормативке |
| 8 | Что остаётся нетронутым |
| 9 | Адаптация контролёров C1-C6 |
| 10 | Гранулярные flag-переключатели + rollback |
| 11 | Фазы реализации |
| 12 | Cost monitoring |
| 13 | Связанные изменения в нормативке |
| 14 | Risk register |
| 15 | Открытые вопросы implementation-уровня |
| 16 | Definition of Done |
| 17 | Связь с другими эпиками |
| 18 | Pre-implementation state inventory |
| 19 | Accepted trade-offs |
| 20 | Что НЕ делается этим эпиком |
| 21 | Changelog v2.0 → v2.1 (новое — все 16 правок) |

---

## 1. Назначение и контекст

### 1.1. Что не так с текущим состоянием

- **Routing-словари вручную поддерживаются в 5 документах.** Tooling §3.3 / CLAUDE.md §3.3 / `docs/routing-off-phase.md` / `docs/router-procedure.md` / PSR_v1 R15 — пересекающееся знание «задача → узел». Каждый новый узел требует ручной правки в нескольких местах.
- **Regex-классификатор `tools/router-classifier.mjs` — ручной word-list (~60 ключевиков на 11 категорий)** (router-classifier.mjs:17-32) не покрывает новые домены (marketing #74-83, infosec #68-73, finance #61-63).
- **§12 hard-rule** принуждает Superpowers skill для 14 типов задач. Это a-priori правило (Pravila v1.4), не выведенное из эмпирики.
- **Brain-governance evidence — собирается, но почти не оценивается.** Episode `outcome` = `unknown` при записи, brain-retro угадывает по тону следующего prompt'а. Ручной labeling 20 эпизодов раз в 2-3 недели даёт 1.3% покрытия выборки за 6 месяцев — статистически недостаточно.
- **Короткие follow-up prompt'ы теряют контекст** (новое в v2.1). Ты пишешь «продумай архитектуру X», я обсуждаю, ты пишешь «да» → диспетчер видит conversation, контекст «работаем над X» теряется в эпизоде «да». Аудитор видит обрубленный эпизод вместо связной задачи.

### 1.2. Что хочется получить через ~6 месяцев

- **Эмпирическая база ~1500 эпизодов**, ~70-80% с заполненным `review.*` от Opus 4.7 subagent ревьюера → пригодна для дистилляции regex.
- **Regex-правила выведены из факта**, не из угадывания.
- **§17 либо подтверждена, либо ослаблена, либо снята** — решение по результатам distillation.
- **LLM-classifier остаётся fallback** для пограничных случаев.
- **Мозг сжат** на ~30-50% за счёт удаления routing-дублей.

### 1.3. Что НЕ делается этим эпиком

См. §20.

---

## 2. Принципы

1. **Эмпирика бьёт теорию — но не в принципе skill-coverage.** §17 — a-priori safety-rail. Trade-off §19.A.
2. **Один touchpoint для владельца.** Только `/brain-retro` + ответы на 3-4 простых вопроса внутри.
3. **Чистота данных vs скорость.** Где конфликтуют — выбираем чистоту.
4. **Гранулярный rollback.** 9 независимых flag-переключателей (было 7 в v2.0, +2 для памятки и inheritance).
5. **Реестр узлов — единый источник routing** (`docs/registry/nodes.yaml`).
6. **Universal coverage — §17.** Default-deny кроме conversation/micro/manual_override/escape-hatch.
7. **Backwards compatibility forward-only.** Schema bumps поэтапные (v4.0 → v4.3).
8. **Cost transparency без cap.** Daily cost dashboard каждым Stop-hook'ом.

---

## 3. Архитектура — общая картина (8 слоёв)

```text
┌──────────────────────────────────────────────────────────────────┐
│ ТВОЙ PROMPT                                                      │
└──────────────────────────────────────────────────────────────────┘
                              ↓
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 1 — Prefilter (regex, $0, ~1мс)                            │
│  Порядок проверки:                                               │
│  1. Manual override («делай через X») → md_override, direct      │
│  2. Continuation («да», «делай», «дальше», ...) → inherit       │
│     предыдущую классификацию из state, помечаем continuation    │
│  3. Acknowledgment («спасибо», «ок») → conversation чистая      │
│  4. Cancellation («нет», «отбой») → conversation + reject flag  │
│  5. Длина <15 И не содержит anchor → conversation, direct       │
│  6. В MICRO_KEYWORDS → micro, direct                            │
│  7. Иначе → передаётся в LLM-classifier                         │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓ (только non-prefilter)
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 2 — LLM-classifier (Sonnet 4.6 + ПАМЯТКА, ~$0.025/prompt)  │
│  Вход: prompt + nodes.yaml capabilities                          │
│  ПАМЯТКА (4 паттерна, ~200 слов в system prompt):                │
│   - brainstorming: ≥3 alternatives со scoring                    │
│   - discovery-interview: ambiguous → no_skill_found              │
│   - writing-plans: single vs chain decomposition                 │
│   - systematic-debugging: bugfix → проверь system/expected/actual│
│  Выход JSON: task_type / recommended_node / recommended_chain    │
│   / alternatives_considered / reason_for_choice                  │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 3 — Embedding (local, $0, ~50мс)                            │
│  ТОЛЬКО для task_type ∉ {conversation, micro, manual_override}   │
│  Pre-warm на SessionStart hook                                   │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 4 — §17 enforcement (router-tool-gate.mjs)                  │
│  warn-only или enforce (mode переключатель)                      │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓
            [ Claude исполняет skill/chain ]
                     ↓
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 5 — Self_assessment (Stop-hook, Opus 4.7, ~$0.03/task)      │
│  Timeout 15сек + retroactive fallback                            │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓
              [ Episode v4.3 готов ]
                     ↓
┌──────────────────────────────────────────────────────────────────┐
│ СЛОЙ 6 — Reviewer SUBAGENT (Task spawn в /brain-retro)           │
│  Полноценный Claude Code subagent с tools=[Read,Grep,Glob,Skill]│
│  Model: claude-opus-4-7                                          │
│  ЦЕНА: $0.30-1.50 per episode (×5-15 vs direct API)              │
│  Может: читать соседние эпизоды (max 10), вызывать systematic-   │
│   debugging / requesting-code-review / brainstorming             │
│  Fallback: при Task crash → direct API call как backup           │
└────────────────────┬─────────────────────────────────────────────┘
                     ↓
        ┌────────────────────────────────────────┐
        ↓                                        ↓
┌──────────────────────────┐  ┌────────────────────────────────────┐
│ СЛОЙ 7 — /brain-retro    │  │ СЛОЙ 8 — /self-retrospect (opt-in)│
└──────────────────────────┘  └────────────────────────────────────┘
                     ↓
        Через ~6 месяцев → ФАЗА 4 DISTILLATION
```

---

## 4. Компоненты по слоям

### 4.1. Слой 1 — Prefilter с 3 группами и inheritance (РАСШИРЕНО v2.1)

**Файл:** `tools/router-classifier.mjs` (расширяется).

**Порядок проверок (важен):**

#### Проверка 1 — Manual override (приоритет №1)

Pattern: prompt начинается с глагола команды + явная ссылка на skill/node.

Regex: `^(делай|сделай|используй|применя[йи]|запусти|вызови)\s+(через|с помощью|skill|skill[оа]м)\s+([\w\-:]+)`

Примеры match:

- «делай через TDD»
- «используй superpowers:brainstorming»
- «вызови billing-audit»

**Fuzzy matching для `requested_node` extraction (закрывает 3.5):** если extracted slug не точно совпадает с node_id в nodes.yaml — пробуем fuzzy match (Levenshtein distance ≤2 или substring match). Если не найден → `requested_node: 'unknown_<extracted>'`, classifier рекомендует, я уточняю у пользователя.

→ `{ task_type: 'manual_override', node: 'direct', source: 'prefilter', requested_node: '<resolved or unknown>' }`

#### Проверка 2 — Continuation (наследование классификации, новое v2.1)

`CONTINUATION_PATTERNS`:

```text
['да', 'делай', 'давай', 'продолжай', 'дальше', 'ага', 'валяй',
 'поехали', 'утверждаю', 'одобряю', 'ок делай', 'хорошо делай', 'согласен делай']
```

**Действие:** если prompt в списке И **возраст предыдущего state ≤ 30 минут** → читать state файл, наследовать `classification` от предыдущего хода. Записать в episode `inherited_from_task_id: <prev_task_id>`, `inheritance_age_minutes: N`.

Если предыдущий state >30 минут или отсутствует → fall through как обычный conversation.

→ `{ task_type: <inherited>, node: <inherited>, source: 'prefilter_inherited', ... }`

**Цепочка state → episode (закрывает B1/B5):** prefilter работает в `router-prehook.mjs` (UserPromptSubmit), а episode пишется в `observer-stop-hook.mjs` (Stop). Inheritance info переезжает так: (1) `router-prehook.mjs` при continuation пишет в `~/.claude/runtime/router-state-<session>.json` блок `inheritance: { inherited_from_task_id, inheritance_age_minutes }`; (2) `observer-stop-hook.mjs` читает state и копирует `inheritance.*` в episode при write. Возраст считается `now - prev_state.timestamp` (timestamp уже есть в state — `router-prehook.mjs:49`).

#### Проверка 3 — Acknowledgment (чистая conversation, новое v2.1)

`ACKNOWLEDGMENT_PATTERNS`:

```text
['спасибо', 'понял', 'ок', 'хорошо', 'отлично', 'верно',
 'круто', 'годится', 'молодец', 'норм']
```

→ `{ task_type: 'conversation', node: 'direct', source: 'prefilter' }`

#### Проверка 4 — Cancellation (отмена, новое v2.1)

`CANCELLATION_PATTERNS`:

```text
['стоп', 'нет', 'отмени', 'отбой', 'не надо',
 'забей', 'хватит', 'достаточно']
```

**Действие:** task_type=conversation, дополнительно state classification обнуляется (`task_type='conversation'`), но в episode записывается `previous_task_id_rejected: <prev_task_id>` для аудитора (закрывает 2.5).

→ `{ task_type: 'conversation', node: 'direct', source: 'prefilter', previous_rejected: true }`

#### Проверка 5 — Short conversation + anchor protection

Длина prompt'а <15 символов И **не содержит anchor**.

**Anchor list (inline в `tools/router-classifier.mjs`, закрывает 3.6 и C5 — список финализирован, ellipsis убран):**

- Существительные (28): `аудит`, `баг`, `план`, `спека`, `фича`, `тест`, `миграция`, `endpoint`, `файл`, `функция`, `класс`, `компонент`, `view`, `модель`, `биллинг`, `маркетинг`, `безопасность`, `пдн`, `регион`, `портал`, `проект`, `сделка`, `лид`, `админка`, `база`, `схема`, `воронка`, `хук`.
- Императивы (10, если длина >30): `проанализируй`, `проверь`, `исправь`, `почини`, `создай`, `добавь`, `удали`, `переименуй`, `улучши`, `расширь`.

Это **стартовый** список (закрыт для v2.2). Расширение — только по факту missed-conversation cases из self-retrospect lessons; при росте >50 слов вынесем в `tools/anchor-words.json`.

#### Проверка 6 — Micro

`MICRO_KEYWORDS`:

```text
['опечатк', 'typo', 'переименуй', 'rename', 'удали мёртв', 'dead code',
 'формат', 'format', 'константу', 'one constant', 'увеличь', 'уменьши',
 'поменяй значени', 'измени константу', 'одну строку', 'bump']
```

→ `{ task_type: 'micro', node: 'direct', source: 'prefilter' }`

#### Проверка 7 — Forward в Слой 2

Если ничего не сработало — содержательный prompt идёт в LLM-classifier.

### 4.2. Слой 2 — LLM-classifier (Sonnet 4.6) + ПАМЯТКА

**Файл:** `tools/router-classifier.mjs` функция `classify()` переписывается.

**Изменения vs текущее:**

- Модель: `claude-haiku-4-5-20251001` → `claude-sonnet-4-6-<YYYYMMDD>` (verified через `anthropic.models.list()` на старте фазы 2).
- `classifyByRegex` Layer 1 → **удаляется** как primary path (logic переезжает в Слой 1 prefilter).
- `shouldEscalate` → удаляется (всегда escalate).
- `HARD_KEYWORD_STEMS` → удаляется.

**Promпт классификатора (с памяткой):**

```text
<system>
Ты классификатор задач для CRM-проекта «Лидерра» (Laravel 13 + Vue 3 + Vuetify 3).

ОБЯЗАТЕЛЬНЫЕ выходные правила:
1. Верни ровно один из: skill ИЛИ chain ИЛИ no_skill_found.
2. "direct" НЕ разрешён. Conversation/micro обрабатываются ДО тебя.
3. Верни топ-3 alternatives_considered со score (0-1) и причиной отклонения.
4. reason_for_choice — конкретно, со ссылкой на capability.
5. recommended_chain — массив из 1-5 skill IDs.
6. Если ни один узел не подходит — no_skill_found=true + suggestion.

=== ПАМЯТКА (4 паттерна, закрывает 1.1) ===

ПАТТЕРН 1 (brainstorming): обязательно рассмотри минимум 3 alternative_considered.
Один кандидат без альтернатив — плохо.

ПАТТЕРН 2 (discovery-interview): если запрос можно интерпретировать двумя+
способами — НЕ угадывай. Верни no_skill_found=true с
no_skill_found_suggestion: "ambiguous — clarify A vs B vs C".

ПАТТЕРН 3 (writing-plans): различай single-step и multi-step.
- Один глагол + объект ("поправь typo") → chain 1 элемент.
- "и"/"потом"/"затем" или подразумевается несколько этапов → chain ≥2 в порядке.

ПАТТЕРН 4 (systematic-debugging): для task_type=bugfix — проверь, чётко ли
описаны system/expected/actual. Если хотя бы одного нет — рекомендуй
superpowers:systematic-debugging (он сам потребует прояснить).

=== РЕЕСТР УЗЛОВ ===
{nodes_block}

=== РЕЕСТР ЦЕПОЧЕК (справочно) ===
{chains_block}

Output — ONLY JSON object, no prose, no code fences.
</system>

<user>
Prompt: {user_prompt}
</user>
```

**`nodes_block`** — генерится из nodes.yaml live (без полей-подсказок):

```yaml
- skill_id: superpowers:brainstorming
  name: Brainstorming
  capabilities: "creative work — exploring user intent, requirements, design before implementation"
  triggers: ["brainstorm", "обсудим", "варианты"]
```

**Output (JSON):**

```json
{
  "task_type": "feature",
  "recommended_node": "superpowers:brainstorming",
  "recommended_chain": ["superpowers:brainstorming", "superpowers:writing-plans"],
  "recommended_chain_id": "L1",
  "reason_for_choice": "архитектурное обсуждение перед изменением behavior",
  "alternatives_considered": [
    { "node": "...", "match_score": 0.6, "rejected_because": "..." }
  ],
  "no_skill_found": false,
  "no_skill_found_suggestion": null
}
```

**`recommended_chain_id` может быть `null`** если chain custom (не из L1-L16) (закрывает 3.2). Тогда только `recommended_chain` array значимый.

**Памятка управляется flag'ом `prompt-enrichment-mode.json`** (`on`/`off`) — можно выключить если паттерны overfit.

**Caching:** hash(prompt) → result. Hit-rate ~5-15%.

**Fallback цепочка:**

1. Sonnet 4.6 down → Haiku 4.5.
2. Haiku down → regex Layer 1 из `tools/router-classifier-regex-fallback.mjs`.
3. Всё down → `{ task_type: 'unknown', node: 'direct', source: 'fallback', degraded: true }`. В чате explicit маркер `[router degraded: <reason>]`.

**Hot-reload classifier mode:** при каждом UserPromptSubmit hook читает `~/.claude/runtime/router-classifier-mode.json`.

**Cost tracking writing:** classifier-call пишет `task_cost.classifier_input/output_tokens` в `~/.claude/runtime/router-state-<session>.json`.

### 4.3. Слой 3 — Embedding layer

**Файл:** `tools/router-embedding.mjs` (новый).

**Модель:** `Xenova/all-MiniLM-L6-v2` — npm `@xenova/transformers`.

**Условие вычисления (закрывает 3.3):** embedding вычисляется ТОЛЬКО для эпизодов с `task_type ∉ {conversation, micro, manual_override}`. На «да», «делай», «спасибо», «делай через TDD» — embedding не считаем (расточительно, никто не будет искать «семантически похожие "да"»).

**Pre-warm на SessionStart:** новый hook `tools/router-embedding-warmup.mjs`.

**Storage:** Base64-encoded float32 array (~2050 chars).

**Fallback:** `prompt_embedding: null` + `embedding_unavailable: true` в `environment`.

### 4.4. Слой 4 — §17 enforcement

**Файл:** `tools/router-tool-gate.mjs` (расширяется).

**Логика §17:**

```javascript
const NON_BLOCKING_TASK_TYPES = ['conversation', 'micro', 'manual_override'];

function shouldBlock(tool, state, responseText, options) {
  const mode = options.mode; // 'warn-only' | 'enforce' | 'off'
  if (mode === 'off') return false;
  if (mode === 'warn-only') return false;

  if (state.classification.no_skill_found === true) return { block: true, reason: 'no_skill_found_block' };
  if (NON_BLOCKING_TASK_TYPES.includes(state.classification.task_type)) return false;
  if (state.skillInvokedThisTurn === true) return false;
  if (decodeRoutingTag(responseText)?.directJustified) return false;
  if (tool === 'Bash' && isReadOnlyBash(options.bashCommand)) return false;
  if (!['Edit', 'Write', 'MultiEdit', 'Bash'].includes(tool)) return false;

  return { block: true, reason: 'direct_in_non_conversation' };
}
```

**Manual override** — обрабатывается prefilter'ом, gate пропускает. Classifier параллельно shadow-evaluates для сравнения.

**Mode переключатель:** `~/.claude/runtime/router-gate-mode.json` → `{"mode": "off" | "warn-only" | "enforce"}`. Default `warn-only` всё bootstrap.

**Permission interaction:** gate ДО permission. Сознательно (разные слои).

### 4.5. Слой 5 — Self_assessment

**Файл:** `tools/observer-stop-hook.mjs` (расширяется).

**Изменения:**

1. Stop-hook timeout 5s → 15s.
2. Опциональный self_assessment call (если timeout позволяет).
3. Retroactive fill — если не успел, episode пишется без него с `self_assessment_pending: true`. Reviewer subagent дозаполняет.

**Prompt:**

```text
<system>
Ты завершил task. Запиши краткую самооценку в JSON. Никакого prose.
</system>
<user>
Original prompt: {prompt}
Recommended node: {recommended_node}
Actual node: {actual_node}
Chain executed: {chain_executed}

Заполни:
- summary: 1-2 предложения. Что выбрал и почему.
- confidence_in_choice: 0.0-1.0
- what_could_be_better: 1 предложение ИЛИ null
- lesson_learned: 1 предложение если ЧТО-ТО НОВОЕ узнал, иначе null
</user>
```

**Стоимость:** ~$0.02-0.04/call.

### 4.6. Слой 6 — Reviewer SUBAGENT (ПЕРЕПИСАНО v2.1)

**Файл агента:** `.claude/agents/reviewer-agent.md` (новый).

**Вызов:** изнутри `/brain-retro` skill controller (главный Claude) делает `Task(subagent_type='reviewer-agent', prompt=<episode JSON>)` для каждого unreviewed эпизода периода.

**Agent specification (`reviewer-agent.md` frontmatter):**

```yaml
---
name: reviewer-agent
description: |
  Independent reviewer of routing decisions for Лидерра brain governance.
  Reads an episode + optional context (max 10 neighboring episodes of same
  task_id), evaluates classifier choice quality, chain quality, agent
  self-assessment accuracy. Returns structured JSON review.
  Used inside /brain-retro skill. NEVER edits files, NEVER commits.
tools: Read, Grep, Glob, Skill
model: opus
---
```

**Что reviewer-agent МОЖЕТ:**

- Read эпизод который ему передан в prompt.
- Read до 10 соседних эпизодов того же task_id из `docs/observer/episodes-*.jsonl` (context bloat control — закрывает 2.3).
- Read nodes.yaml (понять capabilities узлов).
- Invoke `superpowers:systematic-debugging` skill для глубокого разбора failed эпизодов.
- Invoke `superpowers:requesting-code-review` skill для chek-листа качества.
- Invoke `superpowers:brainstorming` skill для перебора alternatives глубже.

**Что reviewer-agent НЕ МОЖЕТ:**

- Edit / Write — нет в tools.
- Bash — нет в tools.
- Делать коммиты.
- Менять nodes.yaml / эпизоды / нормативку.

**Что reviewer-agent ВОЗВРАЩАЕТ:**

```json
{
  "node_quality": "correct | wrong_node | overkill | underkill | disputable",
  "chain_quality": "correct | missing_step | extra_step | wrong_order | n/a",
  "gap_assessment": "acceptable | mistake_should_complete | mistake_should_not_start | n/a",
  "agent_self_assessment_accuracy": "accurate | over_confident | under_confident | no_self_assessment",
  "error_root_cause": "wrong_skill | wrong_tool | wrong_chain_order | external_failure | n/a",
  "alternative_better": "<node_id or null>",
  "outcome_reviewed": "success | soft_success | rework | blocked",
  "reasoning": "1-3 предложения объяснения"
}
```

**Контроллер (я) парсит ответ и пишет в episode:**

- `review.*` поля заполняются.
- `review.reviewer = 'subagent-opus-4-7'`.
- `outcome_reviewed_source = 'subagent_opus'`.
- `review.reviewed_at = nowIso()`.

**Стоимость:** ~$0.30-1.50 per episode (Opus subagent invocation). При ~200 эпизодов = **$60-300 за один /brain-retro**.

**Per-/brain-retro время:** ~17-100 минут вместо 5 минут direct API.

**Fallback (закрывает 2.2 + B2 — путь определён):** если `Task(subagent_type='reviewer-agent', ...)` падает (timeout, crash) — controller вызывает helper `tools/brain-retro-opus-reviewer.mjs` (этот файл **сохраняется из v2.0** именно как fallback handler — НЕ удаляется при переходе на subagent). Helper делает **direct Opus API call** с тем же adaptive review prompt'ом (без subagent capabilities — без cross-episode reading, без skill invocations). Эпизод помечается `review.reviewer = 'direct-opus-fallback'`, `outcome_reviewed_source = 'direct_opus_fallback'`. Если и direct API down — episode остаётся unreviewed (`review.reviewer_error: <msg>`) для следующего /brain-retro.

**Adaptive prompt template** — handles v2/v3/v4 episodes:

- v4: полный prompt с alternatives + self_assessment + chain_gaps.
- v3: без alternatives — prompt спрашивает «оцени на основе rationale».
- v2: без alternatives + self_assessment — prompt спрашивает «оцени на основе triggers + outcome».
- v1: skip.

### 4.7. Слой 7 — /brain-retro skill (расширенный)

**Файл:** `.claude/skills/brain-retro/SKILL.md` (расширяется).

**Description update (закрывает 3.1):** изменить с «Use ONCE PER SPRINT» на «Use каждые 1-2 недели OR при триггере sanity-check threshold». В references/aggregation-template.md тоже sync.

**Новая процедура:**

```text
1. Determine period (как сейчас).
2. Read evidence (v4.*).
3. Read optional notes.
4. Update read-counter.
5. [v2.1] Sanity-check questions:
   - Analyzer выдаёт top-5 candidate questions (через tools/brain-retro-sanity-generator.mjs).
   - Я выбираю 3-4, формулирую на русском.
   - Задаю через AskUserQuestion (multiple-choice + free comment).
   - ПЕРЕД сохранением: применяю tools/observer-pii-filter.mjs к comment (закрывает 3.4).
   - Ответы пишутся в docs/observer/sanity-checks/YYYY-MM-DD.json со schema_version=1
     (закрывает 3.8) + event-stream в эпизоды периода.
6. [v2.1] Reviewer subagent pickup:
   - Для каждого unreviewed episode → Task(subagent_type='reviewer-agent', prompt=ep).
   - Sanity-answers передаются как период context.
   - Controller парсит response, пишет в episode review.* + outcome_reviewed + outcome_reviewed_source.
   - Per-episode try/catch; fallback на direct API при subagent crash.
7. Run analyzer (расширенный для v4 факторов).
8. Aggregate (per references/aggregation-template.md, обновлённый).
9. [v2.1 — opt-in] Если 150+ episodes с review с last self-retrospect:
   - prompt user: «Запустить self-retrospect? (~$2-5, ~3-5 минут)»
   - Если да — call /self-retrospect.
10. Propose candidates for owner review.
11. Save retro note (с sanity-answers + cost report + reviewer stats).
11a. Refresh STATUS.md.
12. Report to user.
```

**Cost report:**

```text
## Cost report за период
- Classifier (Sonnet 4.6 + памятка): $X.XX (Y prompts)
- Self-assessment (Opus): $X.XX (Z task ends)
- Reviewer subagent (Opus, this run): $X.XX (W episodes)
- Reviewer direct-API fallback: $X.XX (V episodes)
- Self-retrospect (if invoked): $X.XX
- Embedding: $0 (local)
Total: $X.XX
```

### 4.8. Слой 8 — /self-retrospect skill (opt-in)

**Файл:** `.claude/skills/self-retrospect/SKILL.md` (новый).

**Триггер:**

1. Явно: `/self-retrospect`.
2. /brain-retro prompt'ит если накопилось 150+ unreviewed-since-last episodes.

**Action:**

1. Read last 150+ episodes с `review.reviewed_at` filled.
2. Compute patterns (без LLM API — pure aggregation):
   - Промахи classifier.
   - Калибровка confidence.
   - Когнитивные ошибки.
3. Write report в `docs/observer/self-retrospect/YYYY-MM-DD.md`.
4. Update `docs/observer/.self-retrospect-counter.json`.
5. `lesson_learned` → новый `memory/feedback_self_calibration_YYYY-MM.md`.
6. Return summary.

**Стоимость:** ~$2-5 (моя current-session Opus inference). **Не нулевой.**

### 4.9. Coverage announcement — прозрачность покрытия задач (новое v2.3)

**Назначение:** заказчик всегда видит, чем покрыта каждая задача (его или внутренняя Claude) — skill / узел / хук / явный `direct`. Видимая поверхность решения классификатора.

**Две поверхности (per brainstorming Q1):**

1. **Проза** — в начале работы над задачей: `Использую <coverage> для <задача>`. Расширение текущей superpowers-конвенции «Using X skill» на узлы/хуки/direct.
2. **TodoWrite** — каждый пункт аннотирован: `<задача> — <coverage>`.

**Формат `<coverage>` (per Q2 — всё):**

```text
skill + узел:  superpowers:test-driven-development (#23 Vitest, #18 Pest)
цепочка:       L1 (brainstorming → writing-plans → executing-plans)
direct:        direct (conversation) | direct (micro: typo) | direct (manual_override)
+ хук:         + §17 gate | pre-edit-normative (когда релевантен)
no_skill:      no_skill_found (нужно расширить реестр)
```

Пример (как в screenshot заказчика): `BalanceCapacityIndicator.vue — superpowers:test-driven-development (#23 Vitest), plan Steps 1-3`.

**Источник данных:** `classifier_output` из `~/.claude/runtime/router-state-<session>.json` (`recommended_node` / `recommended_chain` / `task_type`). Я читаю и показываю. Фактически использованный skill/hook добавляется при исполнении (из execution_trace). Для conversation/micro/manual_override — пометка `direct(<тип>)`.

**Enforcement (per Q3 — convention + reminder):** `~/.claude/hooks/economy-mode.py` (сохраняется по DECISION POINT — economy keep) инжектит в каждый turn короткую строку-напоминание: «аннотируй покрытие задач (skill/node/hook/direct) в прозе + TodoWrite». Плюс правило-конвенция в Pravila §17 (подпункт) + memory feedback. **Не блокирующее** — reminder + конвенция (хук не может написать пометку за Claude, только напомнить).

**Flag:** `~/.claude/runtime/coverage-annotation-mode.json` (`on`/`off`) — 10-й переключатель. Off → пометок нет, строка-напоминание убирается.

**Тайминг (per Q4):** часть router-overhaul, активируется в Phase 3 (когда classifier+observer дают `classifier_output` в router-state). До Phase 3 формальной авто-пометки нет.

**Откат:** flag off; строка-напоминание удаляется из economy-mode.py (snapshot economy-mode уже в archive Task 1).

---

## 5. Schema эпизода v4.* (поэтапные bumps)

| version | когда | что добавляется |
|---|---|---|
| v4.0 | фаза 2 | classifier_output + environment.classifier_model + environment.degraded_mode |
| v4.1 | фаза 3 step 1 | execution_trace + chain_gaps + chain_progress + **inherited_from_task_id + inheritance_age_minutes + previous_direction_rejected** (v2.1 inheritance fields) |
| v4.2 | фаза 3 step 2 | self_assessment + review (template) |
| v4.3 | фаза 3 step 3 | prompt_embedding_base64 + outcome_reviewed + task_cost extended |

**Полная финальная схема v4.3:**

```json
{
  "schema_version": 4,
  "schema_minor": 3,
  "task_id": "...",
  "task_ref": "...",
  "timestamps": { "started_at": "ISO", "ended_at": "ISO" },
  "path_type": "improvised | regulated | mixed | alternative",
  "outcome": "unknown",
  "prompt_signal": "new_task | neutral | correction | approval",

  "decision_provenance": {
    "kind": "autonomous | user_directed_method | user_chose_from_options",
    "claude_would_have_chosen": null,
    "requested_node": null
  },

  "inheritance": {
    "inherited_from_task_id": null,
    "inheritance_age_minutes": null,
    "previous_direction_rejected": false,
    "previous_task_id_rejected": null
  },

  "environment": {
    "economy_level": 100,
    "model": "claude-opus-4-7",
    "classifier_model": "claude-sonnet-4-6-YYYYMMDD",
    "reviewer_model": "claude-opus-4-7",
    "post_compaction": false,
    "session_turn": 1,
    "parallel_session": false,
    "degraded_mode": false,
    "embedding_unavailable": false,
    "prompt_enrichment_active": true
  },

  "task_size": {
    "tool_calls": 0,
    "files_touched": 0,
    "files": []
  },

  "task_cost": {
    "input_tokens": 0,
    "output_tokens": 0,
    "cache_read_input_tokens": 0,
    "cache_creation_input_tokens": 0,
    "classifier_input_tokens": 0,
    "classifier_output_tokens": 0,
    "self_assessment_input_tokens": 0,
    "self_assessment_output_tokens": 0,
    "reviewer_input_tokens": 0,
    "reviewer_output_tokens": 0,
    "reviewer_subagent_usd": 0,
    "reviewer_direct_fallback_usd": 0
  },

  "prompt_embedding_base64": "...",

  "classifier_output": {
    "task_type": "feature",
    "recommended_node": "superpowers:brainstorming",
    "recommended_chain": ["superpowers:brainstorming", "superpowers:writing-plans"],
    "recommended_chain_id": "L1",
    "alternatives_considered": [
      { "node": "...", "match_score": 0.6, "rejected_because": "..." }
    ],
    "reason_for_choice": "...",
    "no_skill_found": false,
    "no_skill_found_suggestion": null,
    "classifier_source": "llm | llm_with_enrichment | regex_fallback | haiku_fallback | prefilter_inherited | unknown"
  },

  "execution_trace": {
    "actual_node_invoked_first": "superpowers:brainstorming",
    "actual_chain_executed": [
      {
        "step": 1,
        "skill": "superpowers:brainstorming",
        "started_at": "ISO",
        "ended_at": "ISO",
        "duration_sec": 1840,
        "completed": true
      }
    ],
    "chain_gaps": [
      {
        "type": "incomplete_chain",
        "expected_steps": 3,
        "executed_steps": 1,
        "gap_after_step": 1,
        "gap_reason": "L1 design-approval gate",
        "gap_severity": "expected | unexpected | error"
      }
    ],
    "chain_deviation": false,
    "deviation_reason": null,
    "deviation_alternative_used": null,
    "chain_progress": []
  },

  "self_assessment": {
    "written_at": "ISO",
    "summary": "...",
    "confidence_in_choice": 0.85,
    "what_could_be_better": null,
    "lesson_learned": null,
    "self_assessment_pending": false
  },

  "review": {
    "reviewed_at": null,
    "reviewer": null,
    "reviewer_error": null,
    "node_quality": null,
    "chain_quality": null,
    "gap_assessment": null,
    "agent_self_assessment_accuracy": null,
    "error_root_cause": null,
    "alternative_better": null,
    "reasoning": null
  },

  "outcome_inferred": null,
  "outcome_reviewed": null,
  "outcome_reviewed_source": null,

  "events": []
}
```

**Sanity-check answers** в `docs/observer/sanity-checks/YYYY-MM-DD-period.json`:

```json
{
  "schema_version": 1,
  "period_start": "ISO",
  "period_end": "ISO",
  "answered_at": "ISO",
  "questions_and_answers": [
    { "q": "...", "a": "yes | no | unsure", "comment_pii_filtered": "..." }
  ]
}
```

Также — duplicate в episodes как `events: [{ kind: 'sanity_check_answer', q, a, comment_pii_filtered, period_id }]`.

**Заметки по типам полей schema (закрывают A1, A2/C3):**

- `review.alternative_better` — в template показан `null`, но при write принимает `string | null` (node_id при `node_quality='wrong_node'`, иначе null). Reviewer возвращает `<node_id> | null` (см. §4.6 + agent file).
- `review.reasoning` / прочие `review.*` — в template `null` (заготовка), при write заполняются reviewer'ом.
- `task_cost` reviewer-поля заполняются **взаимоисключающе по пути**: при subagent-review — `reviewer_subagent_usd` (производное от usage subagent-инвокации); при direct-API fallback — `reviewer_direct_fallback_usd` + `reviewer_input/output_tokens` (прямой API даёт usage в response). Одновременно оба ненулевыми не бывают для одного review-прохода эпизода.
- `outcome_reviewed_source` ∈ `subagent_opus` \| `direct_opus_fallback` \| `opus_proxy` (последнее — историческое из v2.0 direct-API режима).

---

## 6. §17 — формальное определение

**Текст для Pravila:**

> **§17. Universal skill-coverage rule.** Все задачи, кроме явных `conversation`, `micro`, `manual_override`, должны быть покрыты skill или цепочкой из реестра `docs/registry/nodes.yaml`. Direct-исполнение разрешено только для:
>
> 1. **Conversation** — короткие prompt'ы (length < 15 OR в `CONVERSATION_PATTERNS`) без anchor.
> 2. **Micro** — тривиальные правки (опечатка/переименование/format/bump).
> 3. **Manual override** — явное указание «делай через X».
> 4. **Acknowledgment / Cancellation** (v2.1, исправлено v2.2) — короткие follow-up'ы без продолжения работы; обрабатываются prefilter'ом как conversation → direct OK. **Continuation** (да/делай/дальше) в этот exempt-список **НЕ входит** (закрывает D1): она наследует классификацию предыдущего хода, и если та была non-conversation (feature/bugfix/…) — §17 enforcement применяется как обычно. `NON_BLOCKING_TASK_TYPES` в §4.4 содержит только `conversation`/`micro`/`manual_override` — continuation там нет, и это намеренно.
> 5. **Escape-hatch** — `<!-- routing: direct_justified=true reason="..." -->`.
>
> Enforcement через `tools/router-tool-gate.mjs`. Mode: `off | warn-only | enforce`. Default `warn-only` всё bootstrap.
>
> §17 — **не hard-rule под §9 «Отступления»**. Замещает §12 полностью.

**Pravila §12 → удаление, текст в архив.**

---

## 7. Что меняется в нормативке

**Архив:** `docs/archive/llm-bootstrap-2026-05/` со структурой:

- `pravila-12/` — текст §12.
- `routing-docs/` — routing-off-phase.md, router-procedure.md, CLAUDE.md §3.3, PSR_v1 R15.
- `tooling-when-to-use/` — извлечённые поля «когда брать» (inventory подтвердил отсутствие — пусто или NOTE).
- `memory/` — feedback_superpowers_hard_rule.md, feedback_feature_via_writing_plans.md.
- `settings-skill-discipline/` — diff `~/.claude/settings.json` user-level (если есть skill-discipline hooks).
- `nodes-yaml-archive/` — snapshot.
- `ROLLBACK.md`.

Pravila §12 — целиком в архив. §17 добавляется. §16.4 обновляется (missed-activations теперь работают с §17).

CLAUDE.md §3.3 — в архив, заменяется на pin на nodes.yaml. §5 п.11 переписывается.

PSR_v1 R10.1 счётчики → pin на nodes.yaml. R15 удаляется. R0.4.A: §12 → §17.

Tooling Прил.Н — поля «когда брать» в архив. §0 счётчики — pin на nodes.yaml. §3.X cross-refs на router-procedure.md удаляются.

routing-off-phase.md, router-procedure.md — целиком в архив.

nodes.yaml:

- Добавляется `capabilities:` per узел (фаза 2).
- `triggers[]` — остаются.
- L1-L16 chains — остаются.

`tools/observer-classification-map.json` — архивируется (DEPRECATED 24.05, теперь физически удаляется).

---

## 8. Что остаётся нетронутым

- Pravila §1-§11, §13, §14, §15. §16 (только §16.4 minor).
- ADR — все сохраняются.
- Schema БД, открытые вопросы, schema нормативки structure — не трогаются.
- Memory user/project/reference — не трогаются (кроме 2 архивируемых).
- `router-stop-gate.mjs`, `observer-of-observer.mjs`, `observer-coverage-checker.mjs`, экономические хуки, subagent-prompt-prefix.mjs — без изменений.
- Project-skills (`audit-portal`, `regression`, `brain-retro`, `billing-audit`, `security-go-live`) — не трогаются. Capabilities добавляются в nodes.yaml.
- Permission allowlist в settings.json — не трогается.

---

## 9. Адаптация контролёров C1-C6

### 9.1. C1 L1-watcher

Сейчас: `.claude/settings.json` ↔ Tooling §3.3. После: ↔ `docs/registry/nodes.yaml` registered plugins.

### 9.2. C2 Cross-ref-checker

Обновляется список ожидаемых cross-refs (§12 → §17).

### 9.3. C3 Observer-of-observer

Без изменений.

### 9.4. C4 STATUS.md generator

Расширяется секциями: Cost monitoring, Classifier anomaly, Self-retrospect last, Sanity-check coverage, Reviewer subagent vs direct-fallback ratio.

### 9.5. C5 Observer-coverage-checker

Missed-activations логика работает с §17.

**Adapter detail (закрывает A5/B3):** `tools/missed-activations.mjs` сейчас читает `tools/observer-classification-map.json`, который **архивируется** в фазе 1 (task 9). Без правки checker сломается (читает несуществующий файл). Изменение: переключить источник на `docs/registry/nodes.yaml` (classification → recommended nodes выводится из `triggers[].classification` + node capabilities). Новое определение missed-activation под §17: «classifier_output.recommended_node ≠ null, но `actual_node='direct'` без escape-hatch и без manual_override». Конкретная правка — task в фазе 2 (см. §11.2 task 9).

### 9.6. C6 Chain-map-checker

Источник: nodes.yaml chains section.

---

## 10. Гранулярные flag-переключатели + rollback

**10 flag'ов в `~/.claude/runtime/` (было 7 в v2.0, +2 в v2.1, +1 в v2.3):**

| flag-файл | значения | по умолчанию | управляет |
|---|---|---|---|
| `router-classifier-mode.json` | `llm-first` \| `hybrid` \| `regex-first` | `llm-first` после ф.2 | какой classifier работает |
| `router-gate-mode.json` | `off` \| `warn-only` \| `enforce` | `warn-only` всё bootstrap | §17 enforcement |
| `self-assessment-mode.json` | `on` \| `off` | `on` после ф.3 step 2 | Stop-hook self-assessment |
| `reviewer-mode.json` | `subagent` \| `direct-api` \| `off` | `subagent` после ф.3 | reviewer в /brain-retro (v2.1 расширены значения) |
| `self-retrospect-mode.json` | `on` \| `off` | `on` после ф.3 step 3 | /self-retrospect доступен |
| `embedding-mode.json` | `on` \| `off` | `on` после ф.3 step 3 | embedding в episodes |
| `sanity-check-mode.json` | `mandatory` \| `optional` \| `off` | `mandatory` после ф.3 | sanity в /brain-retro |
| `prompt-enrichment-mode.json` (новое v2.1) | `on` \| `off` | `on` после ф.2 | памятка classifier |
| `inheritance-mode.json` (новое v2.1) | `on` \| `off` | `on` после ф.2 | inheritance + 3 группы в prefilter |
| `coverage-annotation-mode.json` (новое v2.3) | `on` \| `off` | `on` после ф.3 | coverage announcement (§4.9) |

**Hot-reload:** каждый component читает свой flag при invocation.

**Полный откат:**

1. Flag'и → pre-overhaul state.
2. `node tools/test-rollback.mjs --dry-run`.
3. `node tools/test-rollback.mjs --execute`.
4. Smoke regression.
5. Время ~1 час.

**Granular откат:** flip один flag, smoke. Inheritance off — короткие prompt'ы возвращаются к чистой conversation без наследования. Памятка off — classifier работает без 4 паттернов.

**Git tag pre-overhaul:** `brain-pre-llm-bootstrap`.

**Dry-run rollback automation:** `tools/test-rollback.mjs` (новый).

---

## 11. Фазы реализации

### 11.1. Фаза 1 — Foundation + delete + archive (~1 неделя)

1. Git tag `brain-pre-llm-bootstrap`.
2. Создать `docs/archive/llm-bootstrap-2026-05/`.
3. Inventory user-level hooks `~/.claude/settings.json`.
4. Архивировать Pravila §12, удалить cross-refs.
5. Удалить skill-discipline hooks из `~/.claude/settings.json` (если найдены).
6. Архивировать routing-off-phase.md, router-procedure.md.
7. Архивировать CLAUDE.md §3.3 → pin на nodes.yaml.
8. Архивировать PSR_v1 R15.
9. Архивировать `tools/observer-classification-map.json`.
10. Архивировать 2 memory-файла.
11. Создать flag-переключатели в `~/.claude/runtime/`.
12. Создать ROLLBACK.md в архиве.
13. Создать `tools/test-rollback.mjs`.
14. Smoke regression.
15. Добавить Pravila §17.
16. Создать ADR-016 «§17 universal skill-coverage».
17. **Inventory `tools/discipline-metrics.mjs` — decide keep/remove (закрывает B4).** Если измеряет only-§12-discipline (которой после удаления §12 не будет) — архивировать вместе с §12; если измеряет общий path_type (нужно дальше) — оставить. Решение фиксируется в commit message фазы 1.
18. Subagent-driven implementation per Pravila §15.1 (это рамка исполнения, не deliverable).

**Выход:** §12 нет, §17 в Pravila, ничего не enforce'ится. Переходное окно 1 неделя.

### 11.2. Фаза 2 — Classifier + памятка + inheritance + §17 logic (~1-1.5 недели)

1. Verify model ID Sonnet 4.6.
2. Заполнить `capabilities:` в nodes.yaml для всех 84 узлов.
3. Переписать `tools/router-classifier.mjs`:
   - **Prefilter с 3 группами + manual override + anchor + micro + continuation inheritance + cancellation + acknowledgment** (закрывает 1.3, 2.4, 2.5).
   - LLM-classifier на Sonnet 4.6.
   - **+ ПАМЯТКА (4 паттерна) в LLM_SYSTEM_PROMPT** (закрывает 1.1).
   - Удалить classifyByRegex primary, сохранить как fallback.
   - Cost tracking writes.
4. Создать `tools/router-embedding.mjs` **с условием skip для conversation/micro/manual_override** (закрывает 3.3).
5. Создать SessionStart hook для warmup.
6. Расширить `tools/router-tool-gate.mjs` (§17 enforcement, warn-only).
7. Расширить `tools/router-prehook.mjs`:
   - Удалить ENFORCEMENT_TYPES whitelist.
   - Использовать новые поля classifier_output.
   - **Inheritance logic** (если continuation pattern → read prev state, наследовать) (закрывает 1.3).
   - **30-минутный таймаут наследования** (закрывает 1.3).
8. Обновить `tools/observer-transcript-parser.mjs` — handle v4.0.
9. **Адаптировать `tools/missed-activations.mjs` (закрывает A5/B3):** переключить источник с archived `observer-classification-map.json` на `docs/registry/nodes.yaml`; новое определение missed-activation под §17 (recommended_node ≠ null + actual_node=direct без escape-hatch/manual_override).
10. Adapt `tools/registry-load.mjs`, `tools/registry-render.mjs`.
11. Smoke regression + integration test.
12. Flip flags `router-classifier-mode → llm-first`, `prompt-enrichment-mode → on`, `inheritance-mode → on`.

**Выход:** новый router работает. Эпизоды v4.0 + inheritance fields. §17 warn-only.

### 11.3. Фаза 3 — Evidence loop (~1.5-2 недели)

**Step 3.1 (~3-4 дня):**

- Расширить `tools/observer-stop-hook.mjs`: execution_trace + chain_gaps writing.
- Bump v4.0 → v4.1 (включая inheritance fields в episode).
- Settings.json: Stop-hook timeout 5s → 15s.

**Step 3.2 (~4-5 дней):**

- Добавить self_assessment в Stop-hook.
- **`.claude/agents/reviewer-agent.md` — УЖЕ создан (commit `49aa4ba7`, 25.05.2026). В фазе 3 step 3.2: verify актуальность + при необходимости обновить system prompt под итоговый review-чек-лист (закрывает 1.2, 2.1, 2.3, A3, A6). Не «создать с нуля» — файл существует.**
- **Сохранить `tools/brain-retro-opus-reviewer.mjs` из v2.0 как direct-API fallback handler (см. §4.6, закрывает B2).**
- Расширить `/brain-retro` skill: шаг 6 теперь делает `Task(subagent_type='reviewer-agent', ...)` per episode.
- **Fallback на direct API при subagent crash (закрывает 2.2).**
- Bump v4.1 → v4.2.

**Step 3.3 (~4-5 дней):**

- Создать `tools/brain-retro-sanity-generator.mjs`.
- Расширить `.claude/skills/brain-retro/SKILL.md`: новые шаги.
- **Обновить description в SKILL.md frontmatter (закрывает 3.1):** «Use каждые 1-2 недели OR при триггере sanity-check threshold».
- **Обновить references/aggregation-template.md** под расширенную процедуру.
- Создать `.claude/skills/self-retrospect/SKILL.md`.
- Расширить `tools/brain-retro-analyzer.mjs` для v4.* факторов + inheritance анализ.
- Расширить `tools/status-md-generator.mjs` для cost + classifier anomaly + self-retrospect + reviewer subagent/fallback ratio секций.
- **Init `docs/observer/.self-retrospect-counter.json` с `{last_run_at: null, episodes_since_last: 0}` (закрывает 3.7).**
- **Init `docs/observer/sanity-checks/` directory.**
- Embedding pre-warm SessionStart hook.
- **PII filter wrapping для sanity comments (закрывает 3.4).**
- **Coverage announcement (§4.9, новое v2.3):** добавить в `~/.claude/hooks/economy-mode.py` строку-напоминание «аннотируй покрытие задач (skill/node/hook/direct) в прозе + TodoWrite»; добавить подпункт-конвенцию в Pravila §17 + memory feedback `feedback_coverage_announcement`; создать flag `coverage-annotation-mode.json`. Источник пометки — `classifier_output` из router-state.
- Bump v4.2 → v4.3.
- Smoke regression.
- Flip flags: self-assessment-mode, reviewer-mode=subagent, self-retrospect-mode, embedding-mode, sanity-check-mode=mandatory, **coverage-annotation-mode=on** → on.

**Выход:** полный evidence pipeline. Reviewer — subagent. Episode v4.3 с inheritance + памяткой.

### 11.P. Passive period (~5-6 месяцев)

- Без implementation work.
- /brain-retro раз в 1-2 недели.
- Mid-bootstrap checkpoint (через 3 месяца).

### 11.4. Фаза 4 — Distillation (~2-3 недели, через ~6 месяцев)

1. Sample selection: `review.node_quality='correct' AND outcome_reviewed in {success, soft_success}`.
2. Кластеризация по embedding.
3. Per-cluster regex extraction.
4. Сборка regex v2.0.
5. A/B тест на holdout.
6. Если accuracy <70% — extend bootstrap.
7. Если ≥70% — flip `router-classifier-mode` → `hybrid`.
8. Обновить nodes.yaml triggers — эмпирические.
9. Решение по §17.
10. Spec результатов в `docs/superpowers/specs/2026-XX-XX-distillation-results.md`.
11. Update ADR-016.

---

## 12. Cost monitoring (без cap, с daily dashboard)

**Что мониторится:**

- `task_cost.classifier_input/output_tokens` × Sonnet 4.6 pricing
- `task_cost.self_assessment_*` × Opus 4.7 pricing
- **`task_cost.reviewer_subagent_usd` — Opus subagent invocation cost (новое v2.1)**
- **`task_cost.reviewer_direct_fallback_usd` — fallback при subagent crash (новое v2.1)**
- Self-retrospect cost при invocation

**Daily aggregation:** `~/.claude/runtime/cost-daily.json`:

```json
{
  "2026-06-15": {
    "classifier_usd": 2.10,
    "self_assessment_usd": 3.40,
    "reviewer_subagent_usd": 0.00,
    "reviewer_direct_fallback_usd": 0.00,
    "self_retrospect_usd": 0.00,
    "total_usd": 5.50,
    "episode_count": 87
  }
}
```

**STATUS.md** секция «Cost monitoring» + `/brain-retro` summary.

**Anomaly detection:**

- Per-episode WARN: `task_cost.classifier_output_tokens > MAX(median × 3, 5000)`.
- Per-day WARN: `total_usd > 1.5 × median_30day`.

**Ожидаемая стоимость (revised v2.1 — reviewer subagent):**

| компонент | $$/мес ожидание |
|---|---|
| Sonnet 4.6 classifier + памятка (50-100 prompt/день × $0.025) | $38-75 |
| Self-assessment в Stop-hook (50-100 task/день × $0.03) | $30-60 |
| Reviewer SUBAGENT (200 episodes × 4 retro/мес × $0.50) | $240-1200 (главный driver) |
| Reviewer direct-fallback (1-5% crashes × $0.05) | $5-15 |
| Self-retrospect (~$2-5 × 2-4 calls/мес) | $10-20 |
| Embedding (локально, только non-prefilter) | $0 |
| **Total** | **$323-1370/мес** |

За 6 месяцев bootstrap: **~$1940-8200**. **Значительно выше v2.0 ($720-1380)** из-за reviewer-subagent (×6-15 vs direct API). Это **сознательный trade-off** за качество review (cross-episode context, skill invocations).

**Если subagent reviewer слишком дорог — granular rollback:** flip `reviewer-mode` → `direct-api`. Возвращаемся к v2.0 стоимости.

---

## 13. Связанные изменения в нормативке

### 13.1. Pravila

- §12 удаляется.
- §17 добавляется (с подпунктами включая Continuation/Acknowledgment/Cancellation от v2.1).
- §16.4 обновляется.
- §0/§1 cross-refs.
- §9 changelog.

### 13.2. CLAUDE.md

- §3.3 удаляется.
- §5 п.11 переписывается.
- §0 cross-refs.
- §9 history.

### 13.3. PSR_v1

- R10.1 счётчики → pin.
- R15 удаляется.
- R0.4.A: §12 → §17.

### 13.4. Tooling Прил.Н

- §4.X «когда брать» удаляются (inventory подтвердил отсутствие).
- §0 счётчики → pin.
- §3.X cross-refs.

### 13.5. nodes.yaml

- `capabilities:` per узел.
- triggers + chains остаются.

### 13.6. ADR-016 (новый)

«§17 universal skill-coverage rule replaces §12». Структура: Status / Context / Decision / Consequences / Boundaries.

---

## 14. Risk register

| риск | вероятность | impact | митигация |
|---|---|---|---|
| Classifier систематически промахивается | средняя | высокий | Reviewer subagent + sanity-check, granular rollback |
| Self-assessment Stop-hook жрёт $$ | высокая | средний | Daily dashboard, flag off |
| Sonnet/Opus API down | средняя | низкий | Fallback chain (Haiku → regex для classifier; direct API для reviewer) |
| Embedding не загружается на Windows | низкая | высокий | Fallback NULL embedding |
| §17 enforcement блокирует legitimate direct | средняя | средний | warn-only всё bootstrap, escape-hatch, rollback |
| Anthropic breaking change в API | средняя | высокий | classifier_model в episode → датасет split; fallback chain |
| Cost runaway | низкая | высокий | Daily dashboard, anomaly WARN, granular rollback ~1 час |
| **Reviewer subagent stoимость взлетает (v2.1)** | **высокая** | **высокий** | **Daily monitoring, flag `reviewer-mode → direct-api` для отката к v2.0 ценам** |
| **Reviewer subagent crashes часто (v2.1)** | **средняя** | **средний** | **per-episode try/catch, fallback на direct API, tracked в episode review.reviewer field** |
| **Reviewer subagent context bloat (v2.1)** | **средняя** | **средний** | **agent system prompt: max 10 соседних эпизодов** |
| Дмитрий не вызывает /brain-retro | средняя | высокий | self-retrospect opt-in, reviewer queue |
| Mid-bootstrap evidence низкого качества | средняя | средний | Checkpoint через 3 месяца |
| Spec устаревает за phase split | низкая | низкий | Refresh check |
| Conversation prefilter false-positive «делай аудит» | низкая | средний | Anchor detection (закрытый риск v2.1) |
| outcome_reviewed качество proxy | средняя | средний | sanity-check + reviewer subagent cross-episode insights |
| Sanity-check вопросы шумные | средняя | низкий | top-5 candidates, калибровка |
| Self-retrospect не находит паттернов первые 3 месяца | высокая | низкий | OK — calibration period |
| nodes.yaml capabilities пропускает узлы | низкая | средний | Subagent task с verification |
| Permission interaction breakage | низкая | высокий | Smoke test |
| **Inheritance переносит неверный контекст (v2.1)** | **средняя** | **низкий** | **30-минутный таймаут, следующее сообщение откатывает; ущерб = 1 лишний tool-call** |
| **Inheritance + manual override приоритет (v2.1)** | **низкая** | **низкий** | **Manual override проверка первая в prefilter (закрыто 2.4)** |
| **PII утечка через sanity-check comments (v2.1)** | **низкая** | **высокий** | **PII filter wraps comment перед сохранением (закрыто 3.4)** |
| **Памятка classifier biases output (v2.2, закрывает A4)** | средняя | низкий | bias про **формат** (≥3 alternatives, ambiguous→no_skill_found), не про **выбор узла** (§19.H); flag `prompt-enrichment-mode → off` если overfit виден в /brain-retro |
| **missed-activations.mjs ломается после архива classification-map (v2.2, A5)** | высокая | средний | task в фазе 2 (§11.2 task 9) — переключение на nodes.yaml до архива в фазе 1 не ломает (checker не вызывается между фазами в проде) |

---

## 15. Открытые вопросы implementation-уровня

**Фаза 1:**

- Точные имена hooks `~/.claude/settings.json` user-level.
- Структура архивных папок.

**Фаза 2:**

- Exact model ID Sonnet 4.6.
- Capabilities-описания узлов — generation strategy.
- Embedding daemon vs per-call (latency).
- recommended_chain хранение: id vs array vs both.
- **Inheritance edge case «да в ответ на мой вопрос с выбором» — переходить ли в decision_provenance.kind=user_chose_from_options (v2.1, deferred to явному triggered case в evidence).**

**Фаза 3:**

- Sanity questions formulation calibration.
- Self-retrospect counter exact threshold.
- Self-retrospect skill description formulation.
- **Reviewer agent system prompt — детальная формулировка чек-листа review (v2.1).**
- **Reviewer agent maximum context cap — 10 эпизодов hard-limit или soft? (v2.1)**

**Фаза 4:**

- Embedding clustering algorithm (DBSCAN/k-means/hierarchical).
- Regex extraction algorithm.
- A/B test threshold.

---

## 16. Definition of Done

### После фазы 3

- ✅ Pravila §12 в архиве, §17 в Pravila, ADR-016 в `docs/adr/`.
- ✅ Skill-discipline hooks (если были) в архиве.
- ✅ Routing-docs в архиве.
- ✅ Sonnet 4.6 classifier работает с verified model ID, **prefilter с 3 группами + inheritance + памятка активны (v2.1)**.
- ✅ §17 enforcement в warn-only mode.
- ✅ Embedding пишется в эпизоды (только non-prefilter), pre-warm SessionStart активен.
- ✅ Schema v4.3 пишется. Парсер handles v1/v2/v3/v4 для read.
- ✅ Self_assessment пишется в Stop-event с retroactive fallback.
- ✅ **Reviewer subagent agent file `.claude/agents/reviewer-agent.md` создан и работает (v2.1)**.
- ✅ /brain-retro: sanity-check (mandatory, с PII filter) + reviewer subagent (с fallback на direct API) + опциональный self-retrospect.
- ✅ /self-retrospect skill доступен (opt-in).
- ✅ Daily cost dashboard обновляется + tracking subagent vs direct-fallback ratio.
- ✅ STATUS.md показывает cost + classifier anomaly + self-retrospect + subagent/fallback ratio.
- ✅ ROLLBACK.md протестирован через `tools/test-rollback.mjs --dry-run`.
- ✅ **9 flag-переключателей работают (v2.1: было 7, +prompt-enrichment + inheritance)**.
- ✅ Регрессия: markdownlint / cross-ref-checker / l1-watcher / observer-coverage / chain-map-checker / lychee / gitleaks — GREEN.
- ✅ nodes.yaml: `capabilities:` заполнен для всех 84 узлов.
- ✅ `docs/observer/.self-retrospect-counter.json` создан.
- ✅ `docs/observer/sanity-checks/` directory создана (закрывает C1 — было typo «existed»).
- ✅ brain-retro SKILL.md description обновлён.
- ✅ `tools/missed-activations.mjs` адаптирован на nodes.yaml (закрывает A5).
- ✅ `tools/brain-retro-opus-reviewer.mjs` сохранён как direct-API fallback handler (закрывает B2).
- ✅ `tools/discipline-metrics.mjs` — keep/remove решено в фазе 1 (закрывает B4).

### Mid-bootstrap (~3 месяца)

- ✅ ~500-700 episodes собрано.
- ✅ ≥70% episodes имеют review.* заполненный.
- ✅ Distribution outcome_reviewed: ≥60% success/soft_success, <10% blocked.
- ✅ Mid-bootstrap checkpoint snapshot.
- ✅ **Reviewer subagent stability: ≥90% Task spawns успешны, <10% fallback на direct API.**

### После фазы 4

- ✅ Дистиллированный regex v2.0 в production.
- ✅ A/B тест accuracy report.
- ✅ Spec результатов.
- ✅ Решение по §17.

---

## 17. Связь с другими активными эпиками

- Биллинг v2 Спек C — отдельный, **не блокирует**. Per user decision (2026-05-24): сначала Спек C, потом overhaul.
- Security go-live — отдельный.
- Other — без зависимостей.

Spec самостоятелен.

---

## 18. Pre-implementation state inventory

### 18.1. Hook files

```text
.claude/settings.json hooks:
- PreToolUse Edit|Write: inline CLAUDE.md edit warning
- PreToolUse Task: tools/subagent-prompt-prefix.mjs
- PreToolUse Edit|Write|MultiEdit|Bash: tools/router-tool-gate.mjs
- PostToolUse Edit|Write: inline markdownlint --fix
- PostToolUse Edit|Write: inline db/schema.sql reminder
- Stop: tools/observer-stop-hook.mjs + tools/router-stop-gate.mjs
- UserPromptSubmit: tools/router-prehook.mjs
```

Skill-discipline hooks в проекте — НЕТ. Если есть — то в `~/.claude/settings.json` user-level.

### 18.2. tools/ inventory

```text
router-classifier.mjs (260 строк) — regex Layer 1 + Haiku Layer 2
router-tool-gate.mjs (112 строк) — §17 enforcement база
router-prehook.mjs (106 строк) — ENFORCEMENT_TYPES whitelist
router-stop-gate.mjs, router-stdin-helper.mjs, router-accuracy-runner.mjs — без изменений
observer-stop-hook.mjs (262 строк) — episode write
observer-transcript-parser.mjs — handles v1/v2/v3
observer-routing-detector.mjs — detects user_directed_method
observer-classification-map.json — DEPRECATED 2026-05-24
observer-pii-filter.mjs, observer-choice-detector.mjs, observer-chain-detector.mjs,
observer-recommended-node.mjs, observer-retrofill-chain-ref.mjs,
observer-state-enricher.mjs, observer-hook-resolver.mjs,
observer-coverage-checker.mjs, observer-chain-map-checker.mjs,
observer-of-observer.mjs — без изменений
cross-ref-checker.mjs (132 строк) — C2
l1-watcher.mjs (75 строк) — C1
brain-retro-analyzer.mjs — будет расширен
status-md-generator.mjs — будет расширен
missed-activations.mjs — адаптирован к §17
discipline-metrics.mjs — inventory & decide keep/remove
registry-load.mjs, registry-render.mjs, registry-to-classification-map.mjs — adapt
```

### 18.3. nodes.yaml структура

Per-node fields: id, name, slug, category, subcategory, status, dormancy_reason, triggers[], boundaries, chain_membership, attributes.

Полей `when_to_use` / `routing_triggers` / `description` / `capabilities` — НЕТ. Фаза 2 добавляет `capabilities:`.

L1-L16 chains: lines 1591-1713.

### 18.4. Pravila §12

Существует, sub-секции 12.1-12.4.

### 18.5. Episode JSONL

239 lines = 5 v1 + 139 v2 + 95 v3.

### 18.6. Memory

Brain-related:

- `feedback_superpowers_hard_rule.md` — архивируется.
- `feedback_feature_via_writing_plans.md` — архивируется.
- `feedback_brain_unused_tools_not_problem.md` — остаётся.
- `feedback_brain_counter_canon.md` — остаётся.
- `project_brain_governance_design.md` — остаётся.
- `project_observer_*` — остаются.

### 18.7. Existing project agents (обновлено v2.2)

В `.claude/agents/`: normative-sync.md, prod-deploy-validator.md, rls-reviewer.md, pest-parallel-debugger.md, **reviewer-agent.md** (УЖЕ создан commit `49aa4ba7` 25.05.2026 — закрывает A6; ранее v2.1 ошибочно писала «будет добавлен в фазе 3»). В фазе 3 step 3.2 — verify + при необходимости обновление system prompt, не создание с нуля.

---

## 19. Accepted trade-offs

### 19.A. §17 как a-priori vs эмпирический

§17 — safety rail для bootstrap. Pure empirical = «всё через direct» = бесполезно для дистилляции.

### 19.B. Переходное окно (1 неделя)

Атомарная фаза 1+2 сложнее. Step-by-step безопаснее. Episodes окна помечаются `bootstrap_transition_week: true`, исключаются из дистилляции.

### 19.C. Sanity-check mandatory

Optional → skip → bias. Mandatory = 3 минуты раз в 1-2 недели.

### 19.D. Cost без cap

Cap = false-security. Daily dashboard ловит runaway в час.

### 19.E. Opus reviewer заполняет outcome_reviewed как proxy

Marker `outcome_reviewed_source: 'subagent_opus' | 'direct_opus_fallback' | 'opus_proxy'`. Это лучшее доступное автоматизированно.

### 19.F. Self-retrospect opt-in

Auto = $30-120/мес стабильно. Opt-in = пользователь решает.

### 19.G. Reviewer subagent ×6-15 vs direct API (v2.1)

Цена $240-1200/мес vs $40-80. Trade-off за: cross-episode reading (real cross-context insights), skill invocations (systematic-debugging для failed cases). Качественный выигрыш для тебя читать в /brain-retro отчётах. Для финального regex distillation эффект минимальный (regex не ловит nuance).

**Принимаем** в пользу качества insights. Если cost оказался невыносим — `reviewer-mode → direct-api`.

### 19.H. Памятка classifier — небольшой bias за чистоту данных (v2.1)

Памятка инструктирует classifier следовать конкретным методологиям (≥3 alternatives, ambiguous → no_skill_found). Это **bias** на «структурированный output», но он именно про **формат**, не про **выбор узла**. Принимаем как worthwhile trade-off.

### 19.I. Inheritance таймаут 30 минут — эвристика, не наука (v2.1)

30 минут выбран эвристически (типичный длительный context-switch). Если эвристика плохая — корректируется по факту через анализ inherited episodes в /brain-retro.

---

## 20. Что НЕ делается этим эпиком

- НЕ трогается Pravila §14, §15, §16 (кроме minor §16.4).
- НЕ трогаются ADR (только cross-ref).
- НЕ трогается db/schema.sql.
- НЕ трогается код Лидерра-портала.
- НЕ трогаются другие эпики.
- НЕ реализуется automated regex-distillation в фазах 1-3.
- НЕ меняется outcome_inferred logic.
- НЕ меняется PII-filter applied to episode write — но **добавляется** PII filter на sanity comments (v2.1).
- НЕ intermediate persistence-режим.
- НЕ A/B «§12 vs §17 vs no-rule».
- НЕ реализуется UI для review (chat-only).
- НЕ Anthropic Workbench integration.

---

## 21. Changelog v2.0 → v2.1 (новое)

### Группа 1 — Решения принятые между v2.0 и v2.1

| # | Изменение | Где в spec |
|---|---|---|
| 1.1 | Памятка classifier (4 паттерна: brainstorming/discovery-interview/writing-plans/systematic-debugging) | §4.2, §10 (новый flag), §11.2, §12 |
| 1.2 | Reviewer как полноценный Claude Code subagent (tools=[Read,Grep,Glob,Skill], model=opus). Новый файл `.claude/agents/reviewer-agent.md`. | §4.6 (rewrite), §4.7, §10 (расширены значения reviewer-mode), §11.3 step 3.2, §12 (cost rewrite), §14, §16 |
| 1.3 | Inheritance + 3 группы коротких prompt'ов (continuation/acknowledgment/cancellation) + 30-минутный таймаут | §4.1, §4.2, §5 (новые поля), §10 (новый flag), §11.2, §14 (закрыт risk) |

### Группа 2 — Edge cases

| # | Изменение | Где |
|---|---|---|
| 2.1 | Reviewer model = opus явно в agent file | `.claude/agents/reviewer-agent.md` frontmatter |
| 2.2 | Reviewer subagent crash → fallback direct API | §4.6, §12, §14 |
| 2.3 | Reviewer context bloat: max 10 соседних эпизодов в system prompt | `.claude/agents/reviewer-agent.md`, §14 |
| 2.4 | Manual override приоритет над inheritance в prefilter | §4.1 |
| 2.5 | Cancellation → state classification clear + previous_task_id_rejected marker | §4.1, §5 |

### Группа 3 — Мелкие упущения

| # | Изменение | Где |
|---|---|---|
| 3.1 | brain-retro SKILL.md description update «раз в 1-2 недели» | §11.3 step 3.3 |
| 3.2 | recommended_chain_id может быть null если custom chain | §4.2, §5 |
| 3.3 | Embedding только для non-prefilter эпизодов | §4.3, §11.2 |
| 3.4 | PII filter wraps sanity-check comments | §4.7 step 5, §11.3, §14 |
| 3.5 | requested_node fuzzy matching fallback | §4.1 |
| 3.6 | Anchor word list inline (initial), вынос в config — потом | §4.1 |
| 3.7 | Self-retrospect counter init в фазе 3 step 3.3 | §11.3 step 3.3 |
| 3.8 | Sanity-check answer file schema_version=1 | §5 |

---

## 22. Changelog v2.1 → v2.2 (закрытие 16 находок 0%-аудита)

### Критическое (1)

| # | Находка | Где закрыто |
|---|---|---|
| D1 | §17 formal text включал Continuation в exempt-список, но Continuation наследует non-conversation classification → §17 enforce должен применяться | §6 п.4 переписан |

### Внутренние несогласованности (6)

| # | Находка | Где закрыто |
|---|---|---|
| A1 | schema `alternative_better` типизирован только как null | §5 заметки по типам |
| A2/C3 | task_cost reviewer-поля (tokens + usd) — связь не описана | §5 заметки по типам |
| A3 | §11.3 step 3.2 «создать reviewer-agent.md» — файл уже создан | §11.3 step 3.2 + §18.7 |
| A4 | prompt-enrichment risk отсутствовал в §14 | §14 +строка |
| A5/B3 | missed-activations.mjs читает archived classification-map | §9.5 + §11.2 task 9 + §14 |
| A6 | §18.7 «reviewer-agent будет добавлен» — уже добавлен | §18.7 |

### Underspecified (5)

| # | Находка | Где закрыто |
|---|---|---|
| B1/B5 | inheritance state → episode chain не описан | §4.1 проверка 2 +абзац |
| B2 | fallback path для reviewer subagent не определён | §4.6 (brain-retro-opus-reviewer.mjs handler) |
| B4 | судьба discipline-metrics.mjs не решена | §11.1 task 17 |

### Typo / ellipsis (4)

| # | Находка | Где закрыто |
|---|---|---|
| C1 | typo «existed» в DoD | §16 |
| C4 | typo «ОНLY» (кириллица) в agent file | `.claude/agents/reviewer-agent.md` |
| C5 | anchor list incomplete (ellipsis) | §4.1 проверка 5 — финализирован 28+10 |

**Итого 16 находок закрыты.** Остаточные implementation-вопросы (точные имена hooks, model ID, clustering algorithm) — в §15, решаются на старте фаз, не блокеры.

---

## 23. Changelog v2.2 → v2.3 (coverage announcement)

| Изменение | Где |
|---|---|
| **§4.9 Coverage announcement (новое)** — прозрачность покрытия задач (skill/node/hook/direct) в прозе + TodoWrite; источник — classifier_output; enforcement через economy-mode reminder; flag `coverage-annotation-mode` | §4.9 |
| §10 flags table — +`coverage-annotation-mode.json` (10-й флаг) | §10 |
| §11.3 Phase 3 — +task coverage announcement (economy-mode reminder + Pravila §17 подпункт + memory feedback + flag) | §11.3 step 3.3 |

Источник: brainstorming 2026-05-25 (Q1 поверхности: проза+TodoWrite; Q2 состав: skill+node+hook+direct; Q3 enforcement: convention+reminder; Q4 тайминг: в составе overhaul Phase 3). Связано: DECISION POINT economy keep (economy-mode сохраняется → reminder туда).

---

**Версия spec:** 2.3 от 2026-05-25.
**Предыдущие версии:** v1.0 (8 ошибок) → v2.0 (перезапись) → v2.1 (16 правок) → v2.2 (16 находок аудита).
**Следующий шаг:** writing-plans для фаз 1+2+3 (план уже есть — plan v1.1, обновляется до v1.2 под §4.9). `.claude/agents/reviewer-agent.md` создан (commit `49aa4ba7`).
