# 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 процедуры).