# Router/Hooks Fixes — Phase 3 (Classifier Pamyatka Extension) Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Расширить PAMYATKA классификатора 4-мя новыми паттернами (5/6/7/8) для закрытия brain-retro #9 кандидатов #7/#1/#8/#10 — classifier должен распознавать «добавь/реализуй» (feature), «исправь баг/regex» (bugfix→Pest), «ошибка на боевом» (Sentry), «много однотипного» (coder-agent).

**Architecture:** Additive — добавляем 4 строки к константе `PAMYATKA` в [tools/router-classifier.mjs:198-213](tools/router-classifier.mjs#L198-L213). PAMYATKA инжектится в `system` блок classifier-prompt'а (cacheable, prompt-caching v2.35) когда `enrichment=true`. Existing patterns 1-4 не правятся (zero regression risk). Snapshot-test на `buildClassifierPromptStructured()` верифицирует наличие новых паттернов в выводе.

**Tech Stack:** Node.js (.mjs), vitest. Sonnet 4.6 (через ProxyAPI) — не тестируется в unit-тестах (стоит денег). Эффективность паттернов — manual eval позже.

---

## Контекст

- **Источник:** brain-retro #9 + self-retrospect 28.05 → 4 кандидата на classifier-обучение.
- **Существующее состояние:** PAMYATKA содержит 4 паттерна (brainstorming, discovery-interview, writing-plans single/multi-step, systematic-debugging for bugfix).
- **Проблема:** classifier не распознаёт:
  - **#7** «добавь X / реализуй Y / сделай Z» если требует ≥3 шагов → должен рекомендовать `writing-plans` chain ≥2 (PATTERN 3 уже частично покрывает, но без feature-specific триггеров).
  - **#1** «исправь баг / regex / catastrophic backtracking» (adr-judge-кейс) → должен рекомендовать `systematic-debugging` chain + Pest (#18) для TDD-фикса. PATTERN 4 говорит «recommend systematic-debugging», но не упоминает chain с Pest.
  - **#8** «ошибка на боевом / клиент сообщил / сломалось у пользователя» → должен рекомендовать Sentry MCP (#34) ПЕРВЫМ. Сейчас классификатор предлагает что угодно.
  - **#10** «напиши N однотипных штук / перенеси все Y по шаблону / обнови импорты в M файлах» → должен рекомендовать coder-agent (#19 через Task tool делегирование). Self-retro: «16 раз reviewer отметил недоиспользование».

- **Метод расширения:** добавить 4 паттерна (5/6/7/8) к PAMYATKA. Existing 4 — не трогать.

---

## File Structure

| Файл | Responsibility | Действие |
|---|---|---|
| `tools/router-classifier.mjs:198-213` | Константа PAMYATKA, инжектится в classifier system-prompt при `enrichment=true` | **Modify** — добавить 4 строки PATTERN 5/6/7/8 |
| `tools/router-classifier.test.mjs` | Тесты на classifier (parsing, prompt-структура) | **Modify** — snapshot/grep-тесты на новые паттерны в `buildClassifierPromptStructured()` output |

NB: не правится `docs/registry/nodes.yaml`, не правится regex-fallback, не правится prefilter, не правится Anthropic prompt-caching infra.

---

## Task 1: PATTERN 5 — «добавь / реализуй / сделай» (#7 feature → writing-plans)

**Files:**

- Modify: `tools/router-classifier.mjs:198-213` (PAMYATKA constant — append PATTERN 5)
- Modify: `tools/router-classifier.test.mjs` (add test verifying PATTERN 5 present in prompt)

### Step 1.1: Write failing test

В `tools/router-classifier.test.mjs` добавить тест в конец существующего `describe('buildClassifierPromptStructured', ...)` блока (либо в новый describe если такого нет). Найти существующее место через grep по `buildClassifierPromptStructured`. Если такого describe нет — добавить отдельный:

```js
describe('PAMYATKA extensions (Phase 3 brain-retro #9)', () => {
  const registry = { nodes: [{ id: '#19', name: 'coder', slug: 'coder', status: 'active', triggers: [] }], chains: {} };

  it('PATTERN 5 (feature → writing-plans) is present in system prompt when enrichment=true', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    expect(system).toContain('ПАТТЕРН 5');
    expect(system).toMatch(/добавь.*реализуй.*сделай|реализуй.*добавь|writing-plans/);
    expect(system).toMatch(/feature.*≥3|≥3.*шаг/);
  });

  it('PATTERN 5 absent when enrichment=false', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: false });
    expect(system).not.toContain('ПАТТЕРН 5');
  });
});
```

### Step 1.2: Run test — FAIL

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 5" 2>&1 | tail -15`
Expected: FAIL — PATTERN 5 не существует в PAMYATKA.

### Step 1.3: Add PATTERN 5 to PAMYATKA

В `tools/router-classifier.mjs` найти константу `const PAMYATKA = ...` (строки ~198-213). Добавить новый паттерн ПОСЛЕ существующего ПАТТЕРН 4 (перед закрывающей backtick'ом). Точный текст:

```
ПАТТЕРН 5 (writing-plans — feature): для task_type=feature если запрос
содержит «добавь», «реализуй», «сделай», «создай функционал», «нужна
фича» И задача требует ≥3 шагов — рекомендуй writing-plans (#19) ПЕРЕД
кодом. Если запрос ≤2 шага («поменяй текст», «добавь поле») — direct ok,
plan излишен.
```

Применить через Edit tool на блок:

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

Заменить начальную строку на:

```js
const PAMYATKA = `=== ПАМЯТКА (8 паттернов) ===
```

И в конец перед закрывающим backtick'ом добавить:

```
ПАТТЕРН 5 (writing-plans — feature): для task_type=feature если запрос
содержит «добавь», «реализуй», «сделай», «создай функционал», «нужна
фича» И задача требует ≥3 шагов — рекомендуй writing-plans (#19) ПЕРЕД
кодом. Если запрос ≤2 шага («поменяй текст», «добавь поле») — direct ok,
plan излишен.
```

### Step 1.4: Run test — PASS

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 5" 2>&1 | tail -15`
Expected: PASS, both tests green.

### Step 1.5: Commit Task 1

```bash
git add tools/router-classifier.mjs tools/router-classifier.test.mjs
git commit -m "$(cat <<'EOF'
feat(classifier): PAMYATKA PATTERN 5 — feature requests → writing-plans (Phase 3 #7)

Closes brain-retro #9 candidate 7: classifier was not recognizing
«добавь / реализуй / сделай» as feature triggers requiring writing-plans
chain (≥3 steps). Self-retrospect 28.05: 0/17 feature tasks invoked
writing-plans. Pattern added to PAMYATKA, injected into system prompt
when enrichment=true.

PATTERN 5 specifically distinguishes:
- ≥3-step feature → writing-plans before code
- ≤2-step micro-feature → direct ok

Header count updated: «4 паттерна» → «8 паттернов».
EOF
)"
```

---

## Task 2: PATTERN 6 — bugfix → systematic-debugging + Pest chain (#1)

**Files:**

- Modify: `tools/router-classifier.mjs:198-213` (PAMYATKA — append PATTERN 6)
- Modify: `tools/router-classifier.test.mjs` (test for PATTERN 6)

### Step 2.1: Failing test

В тот же `describe('PAMYATKA extensions ...)` добавить:

```js
  it('PATTERN 6 (bugfix → systematic-debugging + Pest #18) is present', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    expect(system).toContain('ПАТТЕРН 6');
    expect(system).toMatch(/systematic-debugging.*Pest|Pest.*systematic-debugging|#18/);
    expect(system).toMatch(/regex|catastrophic|backtracking|исправь баг/);
  });
```

### Step 2.2: Run — FAIL

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 6" 2>&1 | tail -10`
Expected: FAIL.

### Step 2.3: Add PATTERN 6

После PATTERN 5 в PAMYATKA:

```
ПАТТЕРН 6 (bugfix-chain — TDD): для task_type=bugfix если фикс касается
живого кода (regex, parser, hook, race condition, catastrophic backtracking,
performance) — рекомендуй CHAIN из 2 узлов: systematic-debugging (анализ
причины) + Pest #18 (test-first для регрессии). PATTERN 4 покрывает выбор
systematic-debugging, PATTERN 6 расширяет до chain с TDD-инструментом.
```

И в header строку обновить:

```js
const PAMYATKA = `=== ПАМЯТКА (8 паттернов) ===
```

(уже сделано в Task 1.)

### Step 2.4: Run — PASS

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 6" 2>&1 | tail -10`
Expected: PASS.

### Step 2.5: Commit Task 2

```bash
git add tools/router-classifier.mjs tools/router-classifier.test.mjs
git commit -m "$(cat <<'EOF'
feat(classifier): PAMYATKA PATTERN 6 — bugfix chain with Pest #18 (Phase 3 #1)

Closes brain-retro #9 candidate 1: classifier recognized bugfix via
PATTERN 4 (→ systematic-debugging) but didn't extend to chain with
Pest #18 for test-first regression coverage.

Real-world driver: adr-judge.py catastrophic backtracking fix (commit
1e1457eb) — should have gone through TDD via Pest, not direct edit.
Reviewer Section A in retro #9 flagged this.

PATTERN 6 extends PATTERN 4 with explicit chain recommendation when
fix touches live code (regex/parser/hook/race/perf).
EOF
)"
```

---

## Task 3: PATTERN 7 — «ошибка на боевом» → Sentry MCP (#8)

**Files:**

- Modify: `tools/router-classifier.mjs:198-213` (PAMYATKA — append PATTERN 7)
- Modify: `tools/router-classifier.test.mjs` (test for PATTERN 7)

### Step 3.1: Failing test

```js
  it('PATTERN 7 (prod error → Sentry MCP #34) is present', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    expect(system).toContain('ПАТТЕРН 7');
    expect(system).toMatch(/Sentry|#34/);
    expect(system).toMatch(/боевой|prod|production|liderra\.ru|клиент сообщ/);
  });
```

### Step 3.2: Run — FAIL

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 7" 2>&1 | tail -10`
Expected: FAIL.

### Step 3.3: Add PATTERN 7

После PATTERN 6 в PAMYATKA:

```
ПАТТЕРН 7 (production runtime errors → Sentry): если запрос упоминает
«ошибка на боевом», «клиент сообщил», «не работает в проде», «liderra.ru
упало», «в логах ошибка», «выкатили и сломалось» — recommended_chain
ОБЯЗАН начинаться с Sentry MCP (#34). Не предлагай чтение кода ПЕРЕД
просмотром реального stack-trace из боевого журнала.
```

### Step 3.4: Run — PASS

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 7" 2>&1 | tail -10`
Expected: PASS.

### Step 3.5: Commit Task 3

```bash
git add tools/router-classifier.mjs tools/router-classifier.test.mjs
git commit -m "$(cat <<'EOF'
feat(classifier): PAMYATKA PATTERN 7 — prod errors → Sentry MCP first (Phase 3 #8)

Closes brain-retro #9 candidate 8: 8 reviewer-Opus marks of "should
have used Sentry first". Self-retrospect 28.05: "симптом с боевого →
гадать по коду вместо Sentry".

PATTERN 7 forces classifier to put Sentry MCP (#34) FIRST in
recommended_chain when prompt indicates production-runtime origin
(«ошибка на боевом», «клиент сообщил», «в логах», etc).

NB: Sentry MCP is currently pending Б-1 deployment per Tooling §4.8,
but pattern is added so classifier produces correct recommendation
once instance is live.
EOF
)"
```

---

## Task 4: PATTERN 8 — «много однотипного» → coder-agent (#10)

**Files:**

- Modify: `tools/router-classifier.mjs:198-213` (PAMYATKA — append PATTERN 8)
- Modify: `tools/router-classifier.test.mjs` (test for PATTERN 8)

### Step 4.1: Failing test

```js
  it('PATTERN 8 (mechanical work → coder-agent via Task) is present', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    expect(system).toContain('ПАТТЕРН 8');
    expect(system).toMatch(/coder-agent|#19|Task tool|субагент/);
    expect(system).toMatch(/однотипн|механич|N одинаковых|перенеси все/);
  });
```

### Step 4.2: Run — FAIL

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 8" 2>&1 | tail -10`
Expected: FAIL.

### Step 4.3: Add PATTERN 8

После PATTERN 7 в PAMYATKA:

```
ПАТТЕРН 8 (mechanical/repetitive → delegation): если задача описана как
«напиши N однотипных», «перенеси все Y по шаблону», «обнови импорты в M
файлах», «массовая правка», «однотипная работа во многих местах» —
рекомендуй coder-agent (#19) через Task tool делегирование. Это
не «обычная фича» (PATTERN 5) — это механическая работа, должна уйти
свежему субагенту, не делаться в основном контексте.
```

### Step 4.4: Run — PASS

Run: `npx vitest run tools/router-classifier.test.mjs -t "PATTERN 8" 2>&1 | tail -10`
Expected: PASS.

### Step 4.5: Commit Task 4

```bash
git add tools/router-classifier.mjs tools/router-classifier.test.mjs
git commit -m "$(cat <<'EOF'
feat(classifier): PAMYATKA PATTERN 8 — mechanical work → coder-agent #19 (Phase 3 #10)

Closes brain-retro #9 candidate 10 + self-retrospect 28.05: 16 reviewer-
Opus marks of "should have delegated to coder-agent". Controller (Opus)
was doing repetitive mechanical work itself, burning big-context budget
on tasks suited for fresh subagent.

PATTERN 8 trains classifier to recognize mechanical/repetitive signals
(«N однотипных», «массовая правка», «по шаблону») and recommend
coder-agent #19 via Task tool delegation.
EOF
)"
```

---

## Task 5: Snapshot regression test — header count + all 8 patterns present

**Files:**

- Modify: `tools/router-classifier.test.mjs` (add overall regression test)

### Step 5.1: Failing test (it WILL pass after Tasks 1-4 if header was bumped)

```js
  it('PAMYATKA header reflects 8 patterns total', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    expect(system).toMatch(/=== ПАМЯТКА \(8 паттернов\) ===/);
  });

  it('all 8 patterns present in correct order', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    const indices = [1, 2, 3, 4, 5, 6, 7, 8].map(n => system.indexOf(`ПАТТЕРН ${n}`));
    // All found
    indices.forEach((idx, i) => expect(idx, `ПАТТЕРН ${i + 1} missing`).toBeGreaterThan(-1));
    // Strictly ascending order
    for (let i = 1; i < indices.length; i++) {
      expect(indices[i]).toBeGreaterThan(indices[i - 1]);
    }
  });

  it('original 4 patterns (brainstorming, discovery, plans, debugging) preserved verbatim', () => {
    const { system } = buildClassifierPromptStructured('тест', registry, { enrichment: true });
    // Check key phrases that ID original 4 patterns — no regression on existing eval baseline.
    expect(system).toContain('минимум 3 alternative_considered');
    expect(system).toContain('discovery-interview');
    expect(system).toMatch(/single-step.*multi-step|multi-step.*single-step/);
    expect(system).toContain('system/expected/actual');
  });
```

### Step 5.2: Run all router-classifier tests

Run: `npx vitest run tools/router-classifier.test.mjs 2>&1 | tail -15`
Expected: ALL PASS (existing tests + new 4 patterns + 3 regression tests).

### Step 5.3: Full tools sweep — verify zero regression

Run: `npx vitest run --exclude=".claude/**" --exclude=".claude.pre-ruflo.bak/**" --exclude="app/**" --exclude="tools/ruflo-*" --exclude="tools/subagent-prompt-prefix*" 2>&1 | tail -10`
Expected: ALL PASS, 0 regression.

### Step 5.4: Commit Task 5

```bash
git add tools/router-classifier.test.mjs
git commit -m "$(cat <<'EOF'
test(classifier): regression guards for 8-pattern PAMYATKA (Phase 3 close)

Three regression tests:
1. Header count reflects 8 patterns
2. All 8 patterns present in strict ascending order (1-8)
3. Original 4 patterns (brainstorming/discovery/plans/debugging) preserved
   verbatim — protects existing accuracy baseline from drift on future
   pamyatka edits.

Closes Phase 3 brain-retro #9 candidates 7/1/8/10.
EOF
)"
```

---

## F: Final verification + push

### Step F.1: Full sweep

Run: `npx vitest run --exclude=".claude/**" --exclude=".claude.pre-ruflo.bak/**" --exclude="app/**" --exclude="tools/ruflo-*" --exclude="tools/subagent-prompt-prefix*" 2>&1 | tail -8`
Expected: ALL PASS.

### Step F.2: Verify-record sentinel

Run: `node tools/enforce-verify-record.mjs pass`
Expected: sentinel written.

### Step F.3: Push (asks user consent before)

```bash
git fetch origin && git rebase origin/main && git push origin main
```

Phase 1+2 rebase precedent: post-commit hook may regenerate `docs/observer/STATUS.md` between rebased commits causing «local changes overwritten by merge». Resolution: `git restore --staged docs/observer/STATUS.md && git restore docs/observer/STATUS.md && git rebase --continue` (repeat per blocked commit).

---

## Roadmap — оставшиеся фазы

| Фаза | Содержание |
|---|---|
| Phase 4 | #9 хук Semgrep на security-edit · #2 measurement enforce-chain-recommendation (отдельный план) |
| Phase 5 | #4 cost-tracker Stop-hook (отдельный план — твоя выделенная фаза) |

---

## Self-Review

**1. Spec coverage:** Phase 3 покрывает кандидатов 7/1/8/10 — каждый имеет собственный Task + commit. Existing 4 PAMYATKA-паттерна не трогаются — explicit regression test (Task 5.1 третий тест) защищает их verbatim.

**2. Placeholder scan:** Все Step'ы — конкретный текст паттернов + точные команды vitest. Нет TBD/TODO. Тексты паттернов готовые к копи-пасту.

**3. Type consistency:** Все паттерны — простые строки в шаблонном литерале `PAMYATKA`. Никаких функций / сигнатур. Header (`8 паттернов`) обновляется в Task 1 и проверяется в Task 5. Regex'ы в тестах используют разные альтернативы для устойчивости к будущим небольшим правкам — `expect(system).toMatch(/x|y|z/)`.

**4. Risk assessment:**

- LLM-classifier не тестируется live (стоит денег). Эффективность паттернов = manual eval.
- Patterns 5-8 удлиняют PAMYATKA примерно на ~400 токенов. Anthropic prompt-caching минимум 1024 токена для Sonnet — registry block (>2000 tokens) уже превышает, без эффекта на cache-rate.
- Order ПАТТЕРН 1 → 8 строгий — если кто-то добавит новый паттерн в середину, Task 5.2 test упадёт. Это intentional regression-защита.

---

## Метаданные

- **Версия:** 1.0 от 2026-05-28.
- **Источник:** brain-retro #9 (candidates 7/1/8/10) + self-retrospect 28.05.
- **User design choice:** "делай дальше" — все 4 паттерна одним планом, additive подход.
- **Не правит нормативку, не правит nodes.yaml, не правит regex-fallback** — только PAMYATKA + tests.
