# Brain-retro #5 — first non-empty reviewer pass

**Дата:** 2026-05-26 (~08:20 MSK).
**Период:** 2026-05-24T13:18Z .. 2026-05-26T05:09Z (~40 часов, **202 эпизода**).
**Аналитик:** `node tools/brain-retro-analyzer.mjs docs/observer/episodes-2026-05.jsonl` + `tools/brain-retro-batch-reviewer.mjs` (новый — see candidate B).
**Уровень анализа:** полный (analyzer + reviewer + sanity).
**Отношение к предыдущему ретро:** надстройка над [2026-05-24-brain-retro.md](2026-05-24-brain-retro.md) (cutoff 2026-05-24T13:18Z).

> `episodeCount=202`, `reviewed=184` (91%), `errors=18` (8.9% API/parse), `observerErrorCount=0`. **Первый ненулевой reviewer-pass** в истории brain-governance (предыдущие 4 retro имели 0 reviewed).

---

## Period & context

40 часов после retro #4 — относительно тихий период (Биллинг v2 Спец C Phase 1 был выкачен ~25.05 вечер, supplier-webhook reliability Phase 1+2+3 ушёл на боевой 26.05 ночь). Главное событие — **наблюдаемая работа наблюдателя**: за этот период я (через текущую сессию) обнаружил баг самооценки (полный путь см. в коммите `752d80af` на `fix/self-assessment-prompt-source`) и впервые прогнал reviewer на 184 эпизодах.

---

## Macro метрики

| метрика | retro #4 (28h) | retro #5 (40h) | дельта |
|---|---|---|---|
| эпизоды | 116 | 202 | +86 (плотнее) |
| path_type regulated | 19.0% | **4.5%** (9/200) | **−14.5 п.п. ⚠️** |
| skill-инвокации | 22 (19%) | 10 (5%) | −14 п.п. |
| missed activations | 9 | 21 (по STATUS.md — на весь файл, period N/A) | — |
| observer_error | 0 | 0 | стабильно |
| reviewed (впервые!) | 0 | **184** | +184 |
| reviewer rework rate | n/a | **11.4%** (21/184) | baseline |

**Главное:** дисциплина роутинга **резко упала** vs retro #4 (regulated 19% → 4.5%, skill-инвокаций 19% → 5%). Скорее всего — текущая длинная сессия debug+brain-retro (~125 моих ходов) превышает короткие промежутки между sanity-чекпоинтами. Эффект «длинной сессии без перезапуска».

---

## Path-type distribution

| path_type | count | % |
|---|---|---|
| improvised | 191 | 95.5% |
| regulated | 9 | 4.5% |

---

## Reviewer outcome distribution (184 reviewed)

| outcome_reviewed | count | % |
|---|---|---|
| soft_success | 118 | 64.1% |
| success | 45 | 24.5% |
| **rework** | **21** | **11.4%** |
| blocked | 0 | — |

`success + soft_success = 88.6%` — большинство задач закрыто, но **11.4% rework** — материальный сигнал.

---

## Reviewer node_quality (184 reviewed)

| node_quality | count | % |
|---|---|---|
| disputable | 108 | 58.7% |
| **correct** | **56** | **30.4%** |
| **wrong_node** | **17** | **9.2%** |
| overkill | 2 | 1.1% |
| underkill | 1 | 0.5% |

**Только 30% решений «correct»** по оценке Opus 4.7. **9% wrong_node** — где явно нужно было идти не direct'ом. Остальные 59% — «disputable» (приемлемо, но не очевидно лучшее).

### Топ нод, которые я игнорировал (alternative_better из wrong_node)

| узел | раз пропущен | назначение |
|---|---|---|
| **#19 superpowers (writing-plans, brainstorming, TDD…)** | **5** | планирование, plan-driven работа |
| **#18 Pest** | **3** | тесты (когда писал код без тестов) |
| #33 claude-md-management | 2 | правка CLAUDE.md (я делал direct Edit) |
| #25 Semgrep | 2 | анализ кода / SAST |
| #30 Frontend Design | 1 | UI design decision |
| #66 laravel-backend-patterns | 1 | backend convention check |
| #62 billing-audit | 1 | биллинг-инвариант |
| #31 UPM | 1 | UI material lookup |
| #11 Pint | 1 | code style fix |

---

## Reviewer chain_quality

| chain_quality | count |
|---|---|
| n/a | 177 |
| missing_step | 6 |
| extra_step | 1 |

`missing_step=6` — chain'ы рекомендовались, но шаг пропускался.

---

## Reviewer agent_self_assessment_accuracy

| accuracy | count | % |
|---|---|---|
| **no_self_assessment** | **172** | **93.5%** ⚠️ |
| accurate | 8 | 4.3% |
| over_confident | 2 | 1.1% |
| under_confident | 2 | 1.1% |

**Подтверждение бага (а)** — 93.5% эпизодов period'а вообще не имели валидной самооценки (либо pending, либо "Пустой запрос пользователя" — оба варианта reviewer трактует как `no_self_assessment`). Этот retro **подтверждает** ценность фикса в коммите `752d80af`. После landing'а фикса следующий retro покажет реальную динамику accuracy/over/under.

---

## Reviewer error_root_cause

| cause | count |
|---|---|
| n/a | 147 |
| **wrong_skill** | **19** | 
| external_failure | 12 |
| wrong_chain_order | 4 |
| wrong_tool | 2 |

`wrong_skill=19` пересекается с `wrong_node=17` — стабильный сигнал «надо было звать другой узел».
`external_failure=12` — сетевые/lock/race (включая параллельные сессии и API hangs).

---

## Sanity-check results

См. [docs/observer/sanity-checks/2026-05-26.json](../sanity-checks/2026-05-26.json).

1. «Что наблюдатель должен был засечь, но не засёк?» → **Не вспомню**.
2. «Случались моменты, когда я выбрал direct, хотя нужен был навык?» → **Не вспомню**.

Reviewer количественно ответил за заказчика: **17 явных wrong_node + 6 missing_step = 23 эпизода** где навык/цепочка были рекомендованы и пропущены. Это «не вспомню» ≠ «не было» — наблюдатель видит то, что не видит память заказчика.

---

## Reviewer errors (не покрыто этой ретрой)

18 эпизодов получили `null` от API (timeout / parse_error / non-2xx). Будут переподняты в следующем retro.

---

## Causal chains

Топ файлов в periode (analyzer factorMatrix не вытащил chains для batch view — глянул вручную):

| файл | эпизодов | контекст |
|---|---|---|
| `docs/observer/episodes-2026-05.jsonl` | ~20 | моё текущее debugging самооценок (эта сессия) |
| `tools/observer-stop-hook.mjs` | 5+ | фикс самооценки (commit 752d80af) |
| `memory/MEMORY.md` | ~10 | memory-sync after big-day events |
| `ПИЛОТ.md` | ~6 | обновления после прод-деплоев |

**Цепочка эта-сессии** (debug→fix→commit→push→retro) — представлена 8-10 эпизодами на текущих 125 turn'ах.

---

## Candidates for owner review

### A. Add `tools/brain-retro-batch-reviewer.mjs` to repo

**Rationale:** этот retro первый, у которого reviewer-pass нашёл реальные сигналы (rework=11.4%, wrong_node=17). Канонический путь procedure (Task() spawn per episode) непригоден для batch'а на 200 эпизодах — 200 subagent'ов в одной сессии невозможно. Я написал `tools/brain-retro-batch-reviewer.mjs` (direct API через ProxyAPI, 5 concurrency, в-place мутация JSONL). Драйвер общий, не ad-hoc.

**Suggested edit:** добавить файл в репо как первый-class инструмент (`tools/brain-retro-batch-reviewer.mjs`), описать в `.claude/skills/brain-retro/SKILL.md` шаг 5b как «canonical for >50 episodes». Стоимость одного прогона ~$10 (Opus 4.7 × 200 × ~0.05).

**Rejection-option:** не добавлять в репо, оставить как локальный one-off. Тогда следующий retro переоткроет ту же проблему.

### B. Дисциплина роутинга в длинных сессиях

**Rationale:** regulated rate **упал 19.0% → 4.5%** за 40 часов. Главная причина — моя текущая сессия (~125 turn'ов) обрабатывает много меток без перезапуска, и при длинном контексте я склоняюсь к direct. Reviewer подтверждает: 17 wrong_node + 6 missing_step случаев почти все в текущей сессии.

**Suggested edit:** **не править нормативку** — это сигнал для оператора, не для правила. Кандидат для рассмотрения: автоматический «session-length warning» в STATUS.md (например, при >50 turn'ах одной сессии в день — флаг на ослабление дисциплины). Можно реализовать в `tools/status-md-generator.mjs` без правки спека.

**Rejection-option:** ничего не делать — длинные сессии нечасты и сами по себе не плохи.

### C. Enforcement of recommended_node when classifier suggests one

**Rationale:** в `wrong_node=17` случаях classifier ЯВНО рекомендовал узел (`primary_rationale.recommended_node` populated), а я пошёл direct. Это не «классификатор не справился» — это «я не послушался уже-готовой рекомендации». Stage 3 router-overhaul пока в warn-only; для случая «recommended_node !== null && node_chosen === 'direct'» — лучший кандидат на первый enforce.

**Suggested edit:** в `tools/router-tool-gate.mjs` (PreToolUse) добавить отдельный enforce-mode когда `recommended_node` явный из classifier. Пока остальные сценарии warn-only — этот один блокирует. Это уже в дорожной карте Stage 4 — приоритезировать.

**Rejection-option:** ждать полного Stage 4 (батч enforce всех сигналов). Сейчас не пилить отдельно.

### D. Confirm fix (а) — повторить retro через 7 дней

**Rationale:** в этой ретре 93.5% эпизодов «no_self_assessment». Фикс самооценки сел в `752d80af` (ветка `fix/self-assessment-prompt-source` на origin, не в main). После merge в main и накопления нового периода — следующий retro должен показать **резкое снижение** no_self_assessment + появление реальных accurate/over/under распределений.

**Suggested edit:** не правка — а контрольное событие. Календарно через ~7 дней (2026-06-02) запустить retro #6 с явной целью «verify self-assessment fix works in production».

**Rejection-option:** доверять unit-тестам, не делать спец-retro. Тогда никто не увидит если фикс не работает на проде.

---

## Behavioral rule check (Pravila §16.4)

- «Не использован ≠ проблема» — соблюдено. Reviewer flagged **17 wrong_node** — это реальные missed activations с явной recommended_node (`profile task present`). Не помечал generic unused-by-design как «zombie».
- Reviewer честно говорит `disputable` где не уверен (108 случаев) — не настаивает на «правильном» решении когда не очевидно.

---

## Cost report (estimated, без cost-daily.json)

| Component | Calls | Tokens (est.) | USD (est.) |
|---|---|---|---|
| Classifier (Sonnet 4.6) | 3 | ~3K in + ~3K out | ~$0.05 |
| Self-assessment (Sonnet 4.6) | ~33 (broken) | ~10K in + ~10K out | ~$0.20 |
| **Reviewer batch (Opus 4.7)** | **184** | **~140K in + ~90K out** | **~$8.85** |
| **Итого ретра #5** | | | **~$9.10** |

NB: cost-daily.json не существует на этой машине. Сумма — оценочная по ProxyAPI ценам.

---

## Self-retrospect trigger status

`docs/observer/.self-retrospect-counter.json` — `last_run_at: null`, `episodes_since_last: 0`.

После ретры #5 bump'ну на +202. Threshold 50 (по spec §4.8 default; в текущем `.self-retrospect-counter.json` поле `threshold` отсутствует — норма из спека). Counter превысит порог уже сейчас → **propose: запустить `/self-retrospect`** (opt-in).

---

## Что НЕ меняется этим retro

- НЕ редактирую `tools/observer-classification-map.json`, `docs/registry/nodes.yaml`, `tools/.node-dormancy.json`, нормативку, code (кроме `tools/observer-stop-hook.mjs` который уже в коммите `752d80af` отдельной ветке).
- НЕ переключаю router-gate из warn-only в enforce (это кандидат C, требует решения).
- НЕ пишу в `episodes-*.jsonl` через ручную правку — только через batch-reviewer (`review.*` + `outcome_reviewed` + `outcome_reviewed_source` поля).
- НЕ trigger'у auto-memory.
- STATUS.md перегенерируется через `node tools/status-md-generator.mjs` (шаг 8a процедуры).
