Files
portal/docs/observer/notes/2026-05-26-brain-retro-6.md
T
Дмитрий 92ba63b41c chore(observer): brain-retro #6 — full reviewer pass (316/316), digital analysis
Period 2026-05-24T00:00Z..2026-05-26T13:18Z (~61h, 317 episodes).
Processed 132 unreviewed episodes via brain-retro-batch-reviewer.mjs
(Opus 4.7 / ProxyAPI, 293.6s, 0 errors). Coverage 100% (316/316), up from
91% in retro #5.

Findings:
  - rework 10.4% (33/316), stable vs retro #5 (11.4%)
  - 132 episodes (41.6%) with gap «recommended, picked direct» — but
    60-70% turned out to be silent regex-fallback false-positives (fixed
    in follow-up commit).
  - rework by group: skill_used 12.0% | direct_no_rec 2.5% |
    direct_ignored_rec 22.7% — delta 20.2 п.п.
  - user_chose_from_options: 0% rework / 0% blocked on 55 episodes —
    brainstorm-pattern is the strongest quality mechanism.
  - 85% episodes без self_assessment — owner подтвердил «бежал слишком
    быстро без остановки» (material signal).

Artefacts:
  - docs/observer/notes/2026-05-26-brain-retro-6.md (25KB)
  - docs/observer/sanity-checks/2026-05-26-brain-retro-6.json
  - STATUS.md regen (C5 488 episodes, missed_activations=21)
  - read-counter + self-retrospect-counter bumped (519 since last)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 17:28:26 +03:00

24 KiB
Raw Blame History

Brain-retro #6 — full reviewer pass + sanity signal

Дата: 2026-05-26 (~19:10 MSK). Период: 2026-05-24T00:00Z .. 2026-05-26T13:18Z (~61 часов, 317 эпизодов). Аналитик: node tools/brain-retro-analyzer.mjs docs/observer/episodes-2026-05.jsonl + tools/brain-retro-batch-reviewer.mjs (limit=200, conc=5, 293.6s wall-clock). Уровень анализа: полный (analyzer + reviewer + sanity). Отношение к предыдущему ретро: надстройка над 2026-05-26-brain-retro.md (retro #5 cutoff 2026-05-26T05:09Z) — закрыл 132 непроверенных эпизода (18 errors-retry из retro #5 + 114 новых после 05:09Z).

episodeCount=482 (весь май, analyzer dedup), reviewed=316/316=100% (в окне периода), observerErrorCount=0, pending=1 (один edge-case без review). Reviewer-проход полный — 0 errors, 0 API сбоев против 18 в retro #5.


Period & context

61 час между retro #5 (~08:20 MSK 26.05) и retro #6 (~19:10 MSK 26.05). Главные события: брейнсторм с вебмастером К1+К2 финализирован (К3-К7 на паузе до фикса baseline-бага LeadRouter), supplier-snapshot-guard выкачен на боевой ~09:55 UTC, enforce-hard-rules holes 1-9 закрыты (1 hotfix 165f1ed9), Phase 2 FK-violation hotfix, билет «изменить баланс через UI» закрыт через админку.

Заказчик попросил /brain-retro после явного указания «хочу с 24.05 но посмотри ревью мы делали частично, прогони тех что не хватает». 132 непроверенных эпизода — это residue retro #5 (18 errors) + всё что копилось после её cutoff.


Macro метрики vs retro #5

метрика retro #5 (40h) retro #6 (61h) дельта
эпизоды 202 317 +115 (плотнее на 61h: 5.2 → 5.2 эп/час, одинаково)
path_type regulated 4.5% 7.3% (23/317) +2.8 п.п. ↗ (восстановление)
skill-инвокации 10 (5%) 23 (7.3%) +2.3 п.п. ↗
reviewer coverage 91% (184/202) 100% (316/316) +9 п.п. (errors 18→0)
reviewer rework rate 11.4% (21/184) 10.4% (33/316) −1 п.п. (стабильно высоко)
node_quality wrong_node 9.2% (17/184) 9.1% (29/316) стабильно
node_quality correct 30.4% 32.8% (104/316) +2.4 п.п. ↗
node_quality disputable 58.7% 56.5% (179/316) 2 п.п.
no_self_assessment 85.0% 85.0% (270/317) стабильно ⚠️
observer_error 0 0 стабильно

Чтение:

  • Регулированность чуть подросла (4.5% → 7.3%) — это всё ещё дно vs retro #4 (19%), но движение в правильную сторону.
  • Reviewer проход безупречный (errors 18 → 0). Скрипт brain-retro-batch-reviewer.mjs стабилен после 752d80af (self-assessment prompt-source fix).
  • ⚠️ Rework rate стабильно высокий (~10-11%) — baseline ещё не двинулся.
  • ⚠️ no_self_assessment стабильно высокий (85%) — заказчик в sanity-чеке подтвердил «не нормально — я бежал вперёд слишком быстро без остановки». Это материальный сигнал.

Path-type distribution

path_type count % rework rate
improvised 294 92.7% 10.6% (31/293 reviewed)
regulated 23 7.3% 9.1% (2/22 reviewed)

Regulated path даёт modest улучшение (10.6 → 9.1 п.п.). Регулирование помогает, но эффект слабый — это значит что часть «improvised» — это короткие conversation-задачи где регулирование избыточно. Discrimination signal — на больших задачах он сильнее.


Reviewer outcome distribution (316 reviewed)

outcome_reviewed count %
soft_success 193 61.1%
success 86 27.2%
rework 33 10.4%
blocked 4 1.3%

success + soft_success = 88.3% — большинство задач закрыто. 10.4% rework + 1.3% blocked = 11.7% задач не на первой попытке.


Reviewer node_quality (316 reviewed)

node_quality count %
disputable 179 56.6%
correct 104 32.9%
wrong_node 29 9.2%
overkill 2 0.6%
underkill 2 0.6%

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

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

#19 superpowers — №1 пропуск (10 раз, 34% всех wrong_node). Это значит для планирования/feature-задач я регулярно выбирал direct.


Конкретные эпизоды wrong_node (для Q4 sanity заказчика)

Заказчик попросил «направь меня на конкретные эпизоды». Топ-3 по убыванию rework-импакта:

1. Direct на feature-задаче → 4726 outuput tokens без plan'а

  • task_ref: 506004ed-5b89-4922-9bb9-88376c9dbd9e (14:13:09)
  • Классификация: planning, recommended_node=#19
  • Выбрано: direct
  • Outcome: rework
  • Reasoning (reviewer): «Agent classified task as planning and recommended #19 but chose 'direct' instead, bypassing the recommended planning node. With 2766/4726 output tokens generated improvisationally on a planning task, the agent should have invoked the planning node rather than answering directly.»
  • Сигнал: classifier правильно поставил recommended_node=#19 в primary_rationale, но controller всё равно пошёл direct. Это разрыв роутинг-цепочки на уровне дисциплины, не классификации.

2. Direct на memory-sync задаче (касающейся MEMORY.md)

  • task_ref: f4c8ef62-1f28-4ee7-a0b9-cc48a98404d7 (13:33:00)
  • Классификация: memory-sync, recommended_node=#33 + chain #12
  • Выбрано: direct
  • Outcome: rework
  • Reasoning: «Memory-sync workflow was bypassed despite touching MEMORY.md, indicating the proper chain steps were skipped.»
  • Сигнал: прямые Edit'ы memory без вызова #33 claude-md-management — повтор старого паттерна (см. CLAUDE.md §5 п.10).

3. Direct на feature-задаче → Globs с таймаутами

  • task_ref: 1ff47cd9-c1e0-4277-ad1b-1f7754f0569a (03:10:49)
  • Классификация: feature, recommended_node=#19
  • Выбрано: direct
  • Outcome: rework
  • Reasoning: «Agent chose 'direct' and proceeded with exploratory Globs that all timed out. The rationale itself flags #19 as recommended, indicating the direct route was a misroute that should not have been started without the proper feature chain.»
  • Сигнал: тот же паттерн что в кейсе 1 — classifier видит #19, controller игнорирует.

Вывод: во всех трёх кейсах classifier правильно идентифицировал нужный узел, но controller (я) выбрал direct игнорируя рекомендацию. Это сигнал для нормативки: routing-gate должен ужесточиться или нужен явный override-механизм с обоснованием.


Reviewer chain_quality (316 reviewed)

chain_quality count %
n/a 296 93.7%
missing_step 12 3.8%
correct 7 2.2%
extra_step 1 0.3%
wrong_order 0

12 missing_step — где была пропущена обязательная фаза цепочки (preflight / plan / verification).


Reviewer agent_self_assessment_accuracy (316 reviewed)

accuracy count %
no_self_assessment 270 85.4%
accurate 38 12.0%
over_confident 4 1.3%
under_confident 4 1.3%

⚠️ 85% эпизодов без self-assessment — это и есть тот самый «бежал слишком быстро без остановки», который заказчик подтвердил в sanity-чеке. См. кандидат B ниже.


Reviewer error_root_cause (316 reviewed)

root_cause count %
n/a 248 78.5%
wrong_skill 36 11.4%
external_failure 19 6.0%
wrong_chain_order 9 2.8%
wrong_tool 4 1.3%

wrong_skill — #1 root_cause среди материальных ошибок (36 эпизодов; 11.4% всех reviewed, 51% non-n/a). Это согласуется с wrong_node=29 — пересекается с тем же паттерном «выбрал не тот канал».


Factor matrix — основные оси

Provenance × outcome (период)

provenance success soft_success rework blocked total rework rate
autonomous (Claude один) 57 167 33 4 261 12.6% ⚠️
user_chose_from_options (заказчик выбрал из моих вариантов) 29 26 0 0 55 0%
user_directed_method 1 n/a

КРИТИЧЕСКИЙ СИГНАЛ: когда заказчик выбирает из предложенных мной вариантов — rework 0%, blocked 0%. Когда я действую автономно — rework 12.6%. Дельта 12.6 п.п. Это значит brainstorm-pattern «3 варианта пользователю» — самый сильный механизм качества за месяц.

Economy level × outcome (период)

economy success soft rework blocked total
100 (default) 84 189 32 4 309 (97.5%)
5 1 1 2
0 2 1 3
none 1 1 2

Распределение по экономии однородно — почти все ходы на 100% (default).

Path_type × outcome (период)

path_type success soft rework blocked total rework rate
improvised 73 186 31 3 293 10.6%
regulated 13 7 2 1 23 9.1%

Regulated path лучше на 1.5 п.п. — слабое преимущество. Discrimination signal: большая часть improvised — короткие conversation-задачи (70 episodes), где regulation излишен.


Discipline by classification

classification episodes trigger match via skill % trigger % skill
analysis 21 8 4 38.1% 19.0%
planning 11 2 2 18.2% 18.2%
bugfix 16 4 5 25.0% 31.3%
feature 15 2 0 13.3% 0% ⚠️

⚠️ Feature-задачи: trigger match 13.3%, via skill 0% — ни одна feature-задача не прошла через #19. Это причина 10 wrong_node→#19. Plan-driven работа сломалась.


Causal chains (file-overlap)

62 цепочки эпизод→эпизод через общие правленые файлы. Топ-3:

  1. MEMORY.md цепочка — внутри ходов брейн-ретро и брейнсторма (8e4bbb0f9328e4a212fb2d881c4313a9bb783ab454910715) — нормально, единая задача.
  2. resources/js/router/index.ts — Plan 5 frontend Tasks 7-11 финал.
  3. SyncSupplierProjectJob.php / Supplier/SyncSupplierProjectsJob.php — supplier-webhook reliability Phase 1+2+3.

Causal chains пока не дают error→fix сигналов — нужен новый матчер «эпизод с rework → следующий эпизод на тех же файлах».


Missed activations

missedActivations.totalMissed в анализе всего месяца = null/keys-only (analyzer-debt: возвращает кortege вместо данных при пустом множестве, см. кандидат C). Внутри периода miss'ы фигурируют через wrong_node=29 и trigger_match гэпы — уже отражены выше.


Sanity-check ответы заказчика

docs/observer/sanity-checks/2026-05-26-brain-retro-6.json:

вопрос ответ
Главная причина переделок? «Не знаю — смотри сам, тебе виднее» (передал на проф. суждение)
85% без самопроверки — норма? «Не нормально — я бежал вперёд слишком быстро без остановки» ⚠️
Blind spot наблюдателя за период? «Ничего конкретного — наблюдатель ОК»
Direct вместо навыка — пример? «Сложно сказать — направь меня на конкретные эпизоды» (3 кейса выше)

Q2 — самый сильный сигнал ретро. Заказчик в явной форме подтвердил то, что показывает агентам self-assessment-accuracy = 85% no_self_assessment.

NB про первый раунд вопросов: первые 2 вопроса я задал на программистском жаргоне («rework», «wrong_skill», «TDD pattern») — заказчик ответил «преформулируя я не програмист» дважды. Перефразировал простым языком на втором раунде. Урок: sanity-questions должны идти на бытовом языке (заказчик — владелец бизнеса, не разработчик; см. memory feedback_plain_language.md).


Reviewer outcome breakdown

источник reviewed %
direct_api_batch (брain-retro-batch-reviewer.mjs) 316 100%
subagent 0
direct_api fallback 0

brain-retro-batch-reviewer.mjs остаётся рабочей лошадкой. Reviewer-agent subagent через .claude/agents/reviewer-agent.md ещё не вызывался в продуктовом потоке (см. кандидат A).


Кандидаты на review заказчиком

Кандидат A — заменить batch-reviewer на reviewer-agent subagent (per spec §4.6)

Сейчас: все 316 review'ев сделаны через brain-retro-batch-reviewer.mjs (direct Opus API). Spec §4.6 говорит: primary reviewer = subagent через Task(subagent_type='reviewer-agent'), batch — это fallback. Что предлагаю: уточнить процедуру /brain-retro шага 5b — добавить fail-fast флаг «если N>50 эпизодов, использовать batch вместо subagent (для скорости), иначе subagent». Или зафиксировать что batch — основной режим, и обновить spec. Стоимость решения: правка .claude/skills/brain-retro/SKILL.md шага 5b + либо spec §4.6 § amend. Опция отказа: оставить как есть — batch работает.

Кандидат B ⚠️ — поднять self-assessment coverage (Q2 sanity сигнал)

Сигнал: заказчик в sanity-чеке подтвердил «бежал вперёд слишком быстро без остановки» на 85% no_self_assessment. Корень: self-assessment-хук срабатывает не на всех задачах (вероятно фильтрация по типу — conversation/micro исключены, но и многие feature/bugfix проходят без него). После 752d80af хук получает реальный prompt, но скорее всего не докручен по покрытию. Что предлагаю: написать спек «расширить self-assessment trigger на все classification ∈ {feature, bugfix, refactor, planning, security}» — это половина unknown'ов превратится в self-assessed. Дополнительно: проверить нет ли тихих сбоев self-assessment-хука (degradedCount=6 за весь май — стоит сверить пересекается ли с no_self_assessment). Опция отказа: принять 85% no_self_assessment как baseline. Не рекомендую — заказчик прямо сказал «не нормально».

Кандидат C — починить missedActivations в analyzer

Симптом: data.missedActivations возвращает строки "totalMissed", "byNode", "byClassification" вместо данных. Похоже на bug в tools/missed-activations.mjs — функция возвращает ключи объекта вместо самого объекта при пустом результате. Что предлагаю: написать failing-test → fix → 0 regressions. Стоимость: ~30 мин TDD. Опция отказа: оставить — missed activations всё равно фигурируют через wrong_node=29 (косвенно).

Кандидат D — нормативно укрепить «direct на feature/planning требует обоснования»

Сигнал: 10 из 29 wrong_node — это feature/planning с recommended_node=#19, где я выбрал direct. Classifier ВИДИТ узел, controller ИГНОРИРУЕТ. Что предлагаю: дополнить enforce-hard-rules / Pravila §17 — если classifier_output.task_type ∈ {feature, planning} И recommended_node=#19 → require routing-tag с обоснованием почему direct (и hook'ом). Это поведенческое правило, не SoT правка — Pravila §17 расширение. Опция отказа: оставить — ждать новых данных.

Кандидат E — sanity-questions всегда на бытовом языке

Сигнал: 2 из 4 вопросов первого раунда отвергнуты заказчиком как «преформулируя я не програмист». Память feedback_plain_language.md это правило фиксирует, но я её нарушил при формировании sanity-вопросов. Что предлагаю: добавить в .claude/skills/brain-retro/SKILL.md шаг 5a отметку «вопросы заказчику — простым языком; не «rework / wrong_skill», а «переделки / выбор не того инструмента»» с парой примеров. Стоимость: правка одного скила, ~10 мин. Опция отказа: доверить контроллеру каждый раз.

Кандидат F — улучшить classifier на «conversation» vs реальная задача

Сигнал: в period'е 230 эпизодов с task_type=unknown (73%!) — classifier не классифицирует большую часть. 70 — conversation, 7 — micro. Это значит большинство ходов вообще не получают recommended_node, что снимает шанс на правильный routing. Что предлагаю: в tools/router-classifier.mjs добавить fallback-классификацию по text-signature (например keyword-based «спросить» → question / «исправь» → bugfix / «доделай» → feature). Сейчас классификатор-LLM возвращает unknown слишком часто. Стоимость: ~1-2 часа на pure-функцию + tests. Опция отказа: ждать накопления данных, чтобы LLM-classifier обучился через few-shot examples.


Self-retrospect trigger status

docs/observer/.self-retrospect-counter.jsonlast_run_at: null, episodes_since_last: 202 (на старте retro #5; bump до сих пор не делался автоматически). Текущая ситуация: counter уже >>50, в retro #5 заказчику было предложено /self-retrospect (пасс) — повторно предлагать не буду, чтобы не утомлять. Если хочется — заказчик помнит про опцию. Bump после ретры #6: +317 → ~519 episodes_since_last (накопительно). Запишу.


Cost report

~/.claude/runtime/cost-daily.jsonне существует на этой машине (как и в retro #5). task_cost-поля в JSONL все по нулям (0/0 input/output tokens по всем 482 эпизодам месяца) — значит хук, который должен писать токены, не пишет. Это технический долг сам по себе — будущий retro не сможет точно отчитаться по стоимости.

Оценка стоимости retro #6 (ProxyAPI Opus 4.7 — $15/M input, $75/M output):

  • 132 эпизода × средний review-промпт ~3.5k input tokens (полный episode JSON + reviewer-prompt) → ~460k input tokens.
  • Output ~150 tokens × 132 ≈ 20k output tokens.
  • input: $15/M × 0.460 = ~$6.90
  • output: $75/M × 0.020 = ~$1.50
  • Total reviewer-пасса retro #6: ~$8.40

Plus classifier-вызовы и self-assessment этой сессии — не учтены (cost-daily.json пуст). Полная цена ретры (включая мой controller-думать-write) — не отслеживается.


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

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

Артефакты этого retro

  • Эта нота: docs/observer/notes/2026-05-26-brain-retro-6.md
  • Sanity-checks ответы: docs/observer/sanity-checks/2026-05-26-brain-retro-6.json
  • Episodes (всё инкрементально, in-place 132 review'нуты): docs/observer/episodes-2026-05.jsonl
  • Read-counter bump: docs/observer/.read-counter.json (last_read_at: 2026-05-26T13:03:40.766Z, read_count_last_period: 4)
  • STATUS.md regen: следующий шаг процедуры.