# Brain-retro — первое ретро мозга по данным наблюдателя **Дата:** 2026-05-20 (12:25 MSK) **Период:** 2026-05-19 .. 2026-05-20 (это первое brain-retro вообще; покрывает всё, что наблюдатель записал на текущий момент) **Источник:** `docs/observer/episodes-2026-05.jsonl` (22 строки) + `docs/observer/.read-counter.json` **Анализатор:** `node tools/brain-retro-analyzer.mjs docs/observer/episodes-2026-05.jsonl` **Уровень анализа:** верхнеуровневый по запросу заказчика («потом углубимся по разделам»); экономия 0%. > Анализатор отчитался: `episodeCount=17`, `v1SkippedCount=5`, `observerErrorCount=0`. Ниже все цифры по 17 v2-эпизодам, если не отмечено иное. --- ## Period 2026-05-19T05:18:16Z .. 2026-05-20T08:12:29Z (5 сессий, 22 эпизода всего; 17 v2-анализируемых). Сессии: | task_id (session_id) | дата | v1 эпизоды | v2 эпизоды | примечание | |---|---|---|---|---| | `553717ec` | 19.05 05:18 .. 10:24 | 5 | 10 | длинная сессия brain-governance Phase A/B/C + factor-analysis ext; компакция между turn 86–91 | | `24acfa10` | 20.05 07:08 | 0 | 1 | ExitWorktree-разовый ход | | `a42e4ba5` | 20.05 07:26 | 0 | 1 | короткая `PowerShell`/`Bash`-проверка | | `dd905ea0` | 20.05 07:25 .. 07:28 | 0 | 1 | apdate `ЭТАЛОН`-семейства memory (11 Edit) | | `98298ec2` | 20.05 07:36 .. 08:12 | 0 | 3 | сегодняшняя «починка наблюдателя» (TDD + verify) | Текущий ход (брейн-ретро 20.05 ~08:25Z+) будет записан Stop-хуком после завершения и в этом ретро ещё **не** учитывается — это нормально по конструкции наблюдателя. --- ## Path-type distribution (v2, n=17) | path_type | count | % | |---|---|---| | improvised | 14 | 82.4% | | regulated | 3 | 17.6% | | alternative | 0 | 0% | | mixed | 0 | 0% | **Чтение:** «Мозг живёт прямым путём». Лишь два эпизода прошли через явный hard-floor §12: №16 (19.05 10:13, systematic-debugging) и №22 (20.05 07:52, TDD + verification-before-completion). Третий «regulated» — №16-ой же эпизод (тот же epoch, после Stop предыдущего короткого). Каждый regulated-эпизод был обоснован профильным триггером (баг наблюдателя + TDD по правке кода). --- ## Outcome distribution (inferred) | outcome | count | % | |---|---|---| | success | 6 | 35% | | unknown | 11 | 65% | | partial | 0 | 0% | | rework | 0 | 0% | | blocked | 0 | 0% | **Чтение:** не было ни одного `correction`-prompt'а от заказчика (next-prompt-sentiment) за период — переделок нет; ни одного `interrupt`; ни одного `unrecovered_error`. 11 «unknown» — это **последние эпизоды задач** или эпизоды, чей след ещё не сменился новой prompt-меткой (6 из 11 — открытые задачи 20.05; 5 — последние в своих task-группах). Это техническое ограничение выборки, не качественный сигнал. > Поле «failure / aborted» из шаблона анализатор не возвращает — он деградирует до «unknown» (см. `inferOutcome` коммент A-1). --- ## Top nodes used (skill_invoked + node_chosen) Из 17 эпизодов **15** имеют `node_chosen=direct` (88%). Только 2 эпизода открыто декларируют узел: | node | times | first | last | |---|---|---|---| | `direct` | 15 | 2026-05-19T08:06Z | 2026-05-20T07:45Z | | `superpowers:systematic-debugging` | 1 | 2026-05-19T10:13Z | 2026-05-19T10:13Z | | `superpowers:test-driven-development` | 1 | 2026-05-20T07:52Z | 2026-05-20T07:52Z | Полный список `skill_invoked` events (4 уникальных): | skill | эпизоды | |---|---| | `superpowers:systematic-debugging` | №16 | | `claude-md-management:claude-md-improver` | №16 | | `superpowers:test-driven-development` | №22 | | `superpowers:verification-before-completion` | №22 | **Все остальные 60+ узлов реестра** за период не использовались. Это **не проблема** (см. memory `feedback_brain_unused_tools_not_problem.md`). --- ## Factor analysis matrix (v2 — из `factorMatrix`) ### `decision_provenance` — главный фактор «rework мой или router's?» | provenance | success | partial | rework | unknown | |---|---|---|---|---| | `autonomous` | 5 | 0 | 0 | 8 | | `user_directed_method` | 1 | 0 | 0 | 2 | | `user_chose_from_options` | 0 | 0 | 0 | 1 | **Чтение:** 76% решений автономные; 18% — заказчик навязал метод; 6% — collaborative-choice (Phase 1.1, routing-gate не блокирует). Метрика **rework = 0 во всех ячейках** — за период нет признаков «rework по моей вине» либо «rework по навязанному методу». Ranking фактора сейчас **inconclusive из-за нулевого rework**. ### `user_directed_method` — что заказчик навязывал | ход | дата | claude_would_have_chosen | контекст | |---|---|---|---| | ep. 7 | 19.05 08:10 | `subagent-driven-development` | сразу после post_compaction (turn 83) | | ep. 8 | 19.05 08:13 | `subagent-driven-development` | следующий ход той же сессии | | ep. 10 | 19.05 08:25 | `brainstorming` | через 12 минут | Все три — turn 83–88 на той же сессии, сразу после `post_compaction=true` (компакция отрезала контекст). **Это паттерн «после компакции заказчик возвращает рулевое».** ### `economy_level` | economy_level | success | unknown | |---|---|---| | `null` | 2 | 2 | | `0` | 0 | 1 | | `5` | 3 | 5 | | `100` | 1 | 3 | `null` = sentinel не поставлен (legacy 4 эпизода 19.05 утром). Прочие — три тарифа (0/5/100) используются равноценно по решению заказчика per task. Никаких корреляций «экономия→outcome» при текущем n=17 не вытащить. ### `model` | model | success | unknown | |---|---|---| | `claude-opus-4-7` | 6 | 11 | Все 17 v2-эпизодов на Opus 4.7. Контрольной группы (Sonnet/Haiku) в данных нет → факторный анализ по модели **невозможен**. Это ожидаемо: subagent-driven-development вызывает Sonnet/Haiku субагентами, чьи трейсы в основной transcript не попадают (Stop-хук пишет только верхнего Claude). ### `post_compaction` | post_compaction | success | unknown | |---|---|---| | `true` | 6 | 5 | | `false` | 0 | 6 | Псевдо-корреляция: все `post_compaction=false` эпизоды относятся к 20.05 (новые сессии, ещё не успели получить `next-prompt`) → все 6 как unknown по конструкции. **Сигнал не валиден.** ### `session_turn` бакеты | bucket | success | unknown | |---|---|---| | `early` (<10) | 0 | 6 | | `late` (≥40) | 6 | 5 | | `mid` (10–40) | 0 | 0 | Та же артефакт-корреляция, что и с `post_compaction`: «early» = новые сессии 20.05 → unknown по техническому ограничению. Истинного сигнала нет. ### `parallel_session` | parallel | success | unknown | |---|---|---| | `true` | 5 | 5 | | `false` | 1 | 6 | 10/17 (59%) ходов шли в режиме параллельных Claude-сессий (Pravila §15 в работе). Outcome по этому фактору inconclusive — нужны более длинные выборки. ### `task_size` | size | success | unknown | |---|---|---| | `small` (<20 tools) | 6 | 9 | | `medium` (20–60) | 0 | 2 | | `large` (>60) | 0 | 0 | 88% эпизодов — small. Два medium-эпизода — №20 (22 tool_calls, 13 files: orientation-read для текущего ретро) и №22 (56 tool_calls, 11 files: текущая TDD-починка наблюдателя). Оба ещё «unknown» по next-prompt. ### `node_chosen` | node | success | unknown | |---|---|---| | `direct` | 6 | 9 | | `superpowers:systematic-debugging` | 0 | 1 | | `superpowers:test-driven-development` | 0 | 1 | Все 6 «success» — direct-эпизоды; оба skill-эпизода ещё unknown (regulated, не было follow-up correction/approval prompt'а). ### `task_classification` | classification | success | unknown | |---|---|---| | `bugfix` | 1 | 0 | | `feature` | 1 | 2 | | `refactor` | 1 | 0 | | `question` | 0 | 2 | | `other` | 3 | 7 | Преобладание `other` (10/17 = 59%) — индикатор того, что классификатор парсера часто не находит явной семантики prompt'а. Это не проблема алгоритма — это просто стиль работы за период (короткие нейтральные ходы по правке нормативки и memory). --- ## Episodes → tasks (из `tasks` анализатора) 11 групп. «turns that are rework» определены как эпизоды, чей `_inferredOutcome === 'rework'`. Таких **0** в этом периоде. | task_ref | эпизодов | turns-rework | |---|---|---| | `553717ec…#1` | 1 | 0 | | `553717ec…#2` | 2 | 0 | | `553717ec…#3` | 1 | 0 | | `553717ec…#4` | 3 | 0 | | `553717ec…#5` | 1 | 0 | | `553717ec…#6` | 1 | 0 | | `553717ec…#7` | 2 | 0 | | `24acfa10…#8` | 1 | 0 | | `a42e4ba5…#9` | 1 | 0 | | `dd905ea0…#10` | 1 | 0 | | `98298ec2…#11` | 3 | 0 | --- ## Causal-chain candidates (из `causalChains`) **0 цепочек** (анализатор вернул пустой массив). Это здоровый сигнал: hot-file фильтр (CLAUDE.md / MEMORY.md / STATUS.md / `episodes-*.jsonl` / `memory/*.md`) корректно отсекает ложные «А упал на X-файле — через 6 эпизодов Б трогает X-файл». Реальных error→fix цепочек по не-горячим файлам наблюдатель не нашёл, что согласуется с low-error профилем периода (3 `error`-event'а — все рутинные «tool_result is_error», ни одного `unrecovered_error`). --- ## Observer health | метрика | значение | оценка | |---|---|---| | `observerErrorCount` | 0 | ✅ зелено — наблюдатель не падал тихо | | `v1SkippedCount` | 5 | ℹ️ legacy: schema v2 раскатан с 2026-05-19T08:06Z; 5 ранее-утренних эпизодов 19.05 (05:18–06:57) — v1 без `environment`/`prompt_signal`/`decision_provenance`, анализатор их корректно отфильтровал | | `retry` events | 4 (в 2 эпизодах) | в норме — №6 (1 retry), №14 (2 retry); все восстановлены | | `error` events | 3 (в 3 эпизодах) | рутинные `tool_result is_error`; **ни одного** `unrecovered_error` (outcome не blocked) | | `time_burn` events | 1 (19m45s в №22) | большой TDD-эпизод, ожидаемо | | `interrupt` events | 0 | нет прерываний | | `parse_gap` events | 0 | парсер не сообщал о пропусках | | `confusion_marker` events | 0 | парсер не пишет такого вида события за период (ожидаемо; маркеры — поведенческое наблюдение, не tool-event) | --- ## Canonical chains L1–L12 hit rate (предварительно) Канонические связки описаны в `docs/routing-off-phase.md` (PSR_v1 R15, Rec4 SYSTEM-аудита). Полная сверка с L1–L12 — задача углубления. Верхнеуровневая оценка: - **Явных L-цепочек 0**, так как 88% эпизодов — `direct`/`improvised`, без декларации canonical chain в `primary_rationale.boundaries_applied` или `triggers_matched`. - **Возможный L-кандидат** в эпизоде №16 (19.05 10:13): связка `superpowers:systematic-debugging` → `claude-md-management:claude-md-improver` — это похоже на «debug-чейн с фиксацией learning'а в CLAUDE.md» (близко к L-связке runtime-debug + infrastructure-edit, но точная маркировка L? — задача углубления). - **Возможный L-кандидат** в эпизоде №22 (20.05 07:52): `superpowers:test-driven-development` → `superpowers:verification-before-completion` — это **классический TDD-чейн** (близок к канонической связке для feature-кода). | chain (предварит.) | times | notes | |---|---|---| | TDD → verification | 1 | ep.22 (текущий) | | systematic-debugging → claude-md-improver | 1 | ep.16 | | Все остальные L1–L12 | 0 | за период не видно | > Пометка для углубления: считать canonical-chain hit rate не по `skill_invoked`-парам (это сильный сигнал, но узкий), а по сочетанию `triggers_matched` + `boundaries_applied` per `routing-off-phase.md`. Сейчас `triggers_matched` и `boundaries_applied` пусты во всех эпизодах — это `primary_rationale` ещё пишется парсером в «минимальном» режиме. --- ## Improvised chains (path_type=improvised, repeated ≥2) Конкретных повторяющихся «node-set»-цепочек не вижу — большинство improvised-эпизодов либо однотонные (один Edit/Read/Bash-набор по разным memory-файлам), либо изолированы. Зато виден **повторяющийся pattern по предметной области**: | pattern (тематический) | эпизодов | candidate L13+? | |---|---|---| | Self-repair наблюдателя (правки `tools/observer-*` или `docs/observer/*`) | 8 из 17 (47%) | нет — это техдолг bootstrap, не повторяющийся бизнес-чейн | | Sync `memory/*.md` после изменений (особенно `project_state.md`/`reference_github.md`) | 3 | нет — это часть «§4.6 self-review» (Pravila) | | Правка `CLAUDE.md`-секций после нормативных bumps | 2 | нет — закрывается обязательным каналом `claude-md-management` | --- ## chain_divergence cases Нет данных — `primary_rationale.candidates_considered` пуст во всех 17 эпизодах, парсер пока не пишет «рассматриваемые альтернативы». В разделе для углубления — улучшить парсер, чтобы вытаскивать candidate-узлы из текста хода (если такие декларации были в reasoning). --- ## Top error classes | error class | count | recovery pattern | |---|---|---| | `tool_result reported is_error` (рутинный) | 3 | retry внутри хода, без эскалации; outcome не blocked | | `unrecovered_error` | 0 | — | | `interrupt` | 0 | — | Тип-распределение — все три «error»-event'а одинаковые («tool_result reported is_error»). Это значит, что парсер не различает классы ошибок ниже этого уровня (известное ограничение — A-1 fix в `inferOutcome`). --- ## confusion_marker hot-spots Нет данных. `confusion_marker` — это event, который должен писаться парсером при обнаружении паттернов сомнения в reasoning Claude. За период парсер не зарегистрировал ни одного → либо подобного не было, либо паттерн распознавания пуст (см. Кандидаты ниже). --- ## Candidates for owner review Все кандидаты ниже — **предложения**, не действия. Заказчик решает, какое (если вообще) применить. ### Candidate 1: «Self-repair наблюдателя» — 47% периода, в норме для bootstrap-фазы - **Тип:** наблюдение, не изменение нормативки. - **Evidence:** 8 из 17 эпизодов трогали `tools/observer-*` или `docs/observer/*` (эпизоды 6, 13, 14, 16, 20, 22 + два косвенно). Episodes-2026-05.jsonl touched в эпизодах 14, 20. Самый «толстый» — №22: 56 tool_calls, 11 файлов, 19m45s — TDD-починка парсера/STOP-хука/PII-фильтра/coverage-checker. - **Чтение:** мозг **сейчас в фазе самовосстановления** (brain governance Phase A/B/C закрыта 19.05 + factor-analysis extension + phase 1.1 — это всё out-of-feature work, инструментальный долг). После того как Phase C завершит «стабилизацию» (lefthook jobs 11–15 работают, observer-of-observer 54w self-prune, STATUS.md generator) — % должен опуститься. - **Suggested action:** **не вмешиваться**. На следующем ретро сравнить % «self-repair» эпизодов; если останется ≥40% при больших n — это будет сигнал к делегации (например, выделить наблюдатель в фоновый daemon, чтобы не отъедал tool-budget основного Claude). - **Cost / risk:** 0 сейчас; ~0 на следующем ретро. ### Candidate 2: «Direct path 88%» — здоровый низкий уровень regulated/skill-инвокаций, но требует контроля - **Тип:** наблюдение + предложение по парсеру. - **Evidence:** только 2/17 эпизодов проходят через hard-floor §12 (`primary_rationale.hard_floor.invoked=true`). Остальные 15 — `direct`. При этом из 15 ни один не упомянул `boundaries_applied` или `triggers_matched` (пустые массивы во всех 17 эпизодах). - **Гипотеза:** парсер пока **не вытаскивает** «незакрытые» triggers/boundaries — он пишет только явные `skill_invoked` events. Это значит, что мы не видим, **сколько раз §12.2 карта могла бы trigger'нуть skill, но Claude пошёл direct**. Без этого нельзя различить «direct правильно (не было триггера)» и «direct неправильно (был триггер, проигнорирован)». - **Suggested action:** в углублённой фазе обсудить расширение парсера так, чтобы он подсвечивал «потенциальные триггеры» (например, факт чтения `superpowers/skills//SKILL.md` без последующего `skill_invoked`, или Bash-команд, типа `gitleaks`/`pest`/`vitest`, не обёрнутых в `verification-before-completion`). Это превратит «не видим, шёл ли мозг мимо карты» в реальную метрику. - **Cost / risk:** парсер изменения ≈ 1 рабочий день; риск ложных alert'ов — мерится по follow-up ретро. ### Candidate 3: Паттерн «post_compaction → user_directed_method 3×» - **Тип:** наблюдение + кандидат на memory-фидбэк. - **Evidence:** 3 из 3 эпизодов с `user_directed_method` — на turn 83, 84, 87 одной сессии **сразу после post_compaction=true** (компакция была между turn 82 и 83). Заказчик навязал: `subagent-driven-development` (×2) и `brainstorming` (×1). - **Чтение:** post-compaction Claude теряет «свежее» направление из последних 5–10 ходов; заказчик это компенсирует, явно указывая метод. Это не bug, это компенсация известного quirk. - **Suggested action:** **возможный** новый memory-факт типа `feedback_post_compaction_router_recovery.md` — «после ``-маркера ход N+1 часто требует явной маршрутизации заказчиком; не сопротивляться»; либо расширить уже существующее `feedback_post_compaction_loss.md` (если есть). Решает заказчик. - **Cost / risk:** 1 memory-файл / 10 строк; риск нулевой. ### Candidate 4: 5 v1-эпизодов 19.05 утра — archive или конверсия - **Тип:** инфраструктурное предложение. - **Evidence:** эпизоды 1–5 в JSONL (05:18–06:57) — без `schema_version`. Анализатор тихо их пропускает (v1SkippedCount=5). Они **есть в файле**, но не участвуют в факторном анализе. - **Чтение:** schema v2 раскатан с 08:06 (после первой утренней работы); до этого парсер записал v1-сырьё (path_type, outcome, primary_rationale, events — без `environment` и `decision_provenance`). Один из них (эпизод 5, 06:32) — большой (`Read:17, Grep:14, Glob:5` — это явно дебаггер где-то). - **Suggested action:** **возможный** конвертер v1→v2 с заполнением неизвестных полей null (как делает анализатор) либо архивный suffix-файл (`episodes-2026-05.v1-archive.jsonl`). Сейчас оба варианта живы в одном файле без помех. - **Cost / risk:** 0 если оставить; ~2 часа если делать конвертер. ### Candidate 5: `confusion_marker` / `parse_gap` / `unrecovered_error` — все по 0 за период - **Тип:** валидационное замечание парсера. - **Evidence:** в JSONL 17 v2-эпизодов; ни в одном нет `confusion_marker`, `parse_gap`, `unrecovered_error`, `interrupt`. Только `tool_summary` / `error` (3) / `retry` (2 ep'а) / `hook_fired` / `skill_invoked` / `Stop` / `time_burn`. - **Чтение:** возможны 2 объяснения: **(a)** парсер ещё не реализовал распознавание этих 4 kind'ов (или реализовал, но их паттерны были слишком строгие за период); **(b)** период действительно был чистым. - **Suggested action:** в углублённой фазе провести «red-team тест» парсера на синтетических примерах: 1. Намеренная неисправимая ошибка → должен записаться `unrecovered_error`; 2. Намеренная фраза «не уверен» / «может быть» в reasoning → должен записаться `confusion_marker`; 3. Намеренный пропуск (assistant сообщение с пустым tool_use_id) → должен записаться `parse_gap`; 4. Пользовательский `[ESC]` → должен записаться `interrupt`. - **Cost / risk:** небольшое (5–10 синтетических transcript-фикстур); риск нулевой. ### Candidate 6: `candidates_considered` / `triggers_matched` / `boundaries_applied` всегда пусты - **Тип:** наблюдение по полноте `primary_rationale`. - **Evidence:** во всех 17 v2-эпизодах эти три массива — `[]`. Только `node_chosen` и `task_classification` заполнены. - **Чтение:** парсер пишет только финальное решение, не аргументацию. Это известный gap (см. spec §6 «routing_decision события»). - **Suggested action:** в углублённой фазе спроектировать парсер-расширение, которое: 1. Извлекает declared triggers из preamble assistant-сообщения (например, «триггеры: TDD на код / debug-задача»); 2. Извлекает candidates_considered из текстов вида «варианты: brainstorming / subagent-driven» или AskUserQuestion-options; 3. Извлекает boundaries_applied из явных упоминаний ADR/Pravila §N. - **Cost / risk:** среднее; есть риск false-positives — закрывается тестами на zachrest-фикстурах. ### Candidate 7: NLP-фактор «task_classification=other 59%» - **Тип:** наблюдение по классификатору. - **Evidence:** 10 из 17 (59%) — `other`. `bugfix` 1, `refactor` 2, `feature` 3, `question` 2, остальные `other`. - **Чтение:** классификатор парсера задаёт grobые корзины. «Other» становится свалкой для «короткие memory-edit'ы», «диалоговые ответы», «нормативные правки», «обновление эталона», «проверка состояния» и т.п. - **Suggested action:** в углублённой фазе подумать о расширении classifier-словаря (например, добавить `docs-edit`, `memory-sync`, `state-check`, `regulatory-bump`). Это уменьшит «other»-bucket и сделает факторный анализ острее. - **Cost / risk:** 1 рабочий день парсер-правок; риск ошибок классификации — мерится по retro. --- ## Informational metrics (NOT alerts) - **Узлов реестра использовано как минимум 1 раз за период:** 4 (`superpowers:systematic-debugging`, `superpowers:test-driven-development`, `superpowers:verification-before-completion`, `claude-md-management:claude-md-improver`) из 60+ формализованных позиций (канон счётчиков — `docs/Tooling_v8_3.md` §0). - **Узлов реестра не использовано ни разу:** ~56+ из 60+. **Это не проблема** per `feedback_brain_unused_tools_not_problem` (память). Capability-readiness — осознанная стратегия заказчика. - **Hot-files** (по `task_size.files`, с дедупом): `CLAUDE.md` (3 раза), `project_brain_governance_design.md` (3), `reference_github.md` (3), `episodes-2026-05.jsonl` (2), `2026-05-19-observer-factor-analysis-design.md` (2), `tools/observer-transcript-parser.mjs` (2), tools/observer-transcript-parser.test.mjs (2). Остальные 30+ файлов — один раз. - **Самый длинный эпизод:** №22 (20.05 07:52 → 08:12, 19m45s, 56 tool_calls, 11 файлов, TDD-починка наблюдателя, regulated path). - **Самый короткий эпизод:** №2 (19.05 06:07–06:08, 1m, 0 tool_calls — диалоговый ответ). --- ## Что **не** делалось в этом ретро (явные ограничения) 1. **Не сверял с `docs/routing-off-phase.md` L1–L12 канонические связки** — пометил для углубления. 2. **Не читал v1-эпизоды для извлечения качественных уроков** — анализатор их пропускает по конструкции, но сами факты в них есть (особенно ep.5 — большой Read+Grep дебаг-эпизод 19.05 06:32). 3. **Не оценивал latency хуков** — данные есть (`hook_fired.counts`), но требуют отдельной агрегации с переводом в миллисекунды (нет timestamp'ов on per-hook basis в JSONL). 4. **Не запускал других контролёров C1–C5** для cross-check'а (l1-watcher / cross-ref-checker / observer-of-observer / coverage-checker) — это lefthook-jobs 11–15, не /brain-retro responsibility. 5. **Не правил никакую нормативку** — read-only, как требует procedure step 7. 6. **Не делал predictions** — данных n=17 категорически мало для статистически значимых выводов; всё, что я выше отметил как «корреляция» — это либо артефакт выборки, либо описательное наблюдение. --- ## Подпись и провенанс ретро Анализатор — `tools/brain-retro-analyzer.mjs` (commit `e6d6bab` в текущем checkout). Шаблон — `.claude/skills/brain-retro/references/aggregation-template.md`. Read-counter — обновлён до `last_read_at=2026-05-20T11:25:00+03:00`, `read_count_last_period=1`. Эта нота — read-only вывод; никакая нормативная правка не выполнена. --- # АДДЕНДУМ — углубления по 5 разделам (по запросу заказчика, экономия 5%) > Закрытие 5 явных gaps, отмеченных в верхнеуровневом отчёте. Read-only, > никаких правок нормативки. Данные собраны 2026-05-20 ≈11:35 MSK. ## A. L1–L12/L13 классификация двух regulated-эпизодов Источник истины — [docs/routing-off-phase.md](../../routing-off-phase.md) v1.2 (20.05.2026, 12 канонических + L13 finance-tooling). **Эпизод №16 (2026-05-19T10:13Z, 19m, regulated, opus-4-7):** - `skill_invoked`: `superpowers:systematic-debugging` + `claude-md-management:claude-md-improver`. - Файлы: `tools/observer-transcript-parser.{mjs,test.mjs}` + `CLAUDE.md` + transcript-jsonl сессии. - **Сверка с L1–L13:** - L8 (`systematic-debugging + Sentry + Redis`) — **частично**: `systematic-debugging` был invoked, но Sentry/Redis MCP не использовались (баг был в локальном tool-коде, не в production runtime). - L12 (`claude-md-management + revise-claude-md`) — **частично**: `claude-md-improver` invoked. Это один из двух entry-skill'ов L12. `/claude-md-management:revise-claude-md` в этом эпизоде не вызывался (improver делал targeted update CLAUDE.md, не capture session-learnings). - **Вердикт:** эпизод **не маппится 1:1** на каноническую L-связку. Это **гибрид Pravila §12.2 hard-floor** (systematic-debugging при unexpected behavior) **+ §5 п.10 обязательного канала** (правка CLAUDE.md только через claude-md-management). Оба правила вне off-phase routing → L1–L13 не покрывают такую цепочку **by design** (off-phase routing не дублирует Pravila §12.2/§5 п.10 hard-rules — это явно в routing-off-phase §11.5 «Hard-rules перевешивают routing-аид»). **Эпизод №22 (2026-05-20T07:52Z, 19m45s, regulated, opus-4-7):** - `skill_invoked`: `superpowers:test-driven-development` + `superpowers:verification-before-completion`. - Файлы: 11 `tools/observer-*` + `.gitleaks.toml` (test-fixture seam с false-positive). - **Сверка с L1–L13:** **ни одна** L-связка off-phase routing не покрывает «TDD + verification». L1–L13 — это off-phase инструменты (#31–#63), TDD/verify — это Pravila §12.2 hard-floor (Superpowers). Тоже не дублируется в routing-аиде. - **Вердикт:** **чистый Pravila §12.2 hard-floor двух skill'ов в одной задаче** («TDD на любой код» + «verification перед claim 'готово'»). L-маркировка неприменима. **Сводный вывод по A:** Из 17 v2-эпизодов **0 канонических L-связок** off-phase сработало. Все 2 regulated-эпизода прошли через **Pravila §12.2 hard-floor** (skill из обязательной карты §12.2), не через каноническую цепочку L1–L13. **Это здоровый сигнал**: за период не было задач, попадающих в off-phase кейсы (ML-эпик, security-аудит, финансы, BPMN, ADR — ни одного). Все turn'ы — самообслуживание наблюдателя и правки нормативки/memory. | chain | times | вердикт | |---|---|---| | L1 discovery→brainstorm→writing-plans→subagent-driven | 0 | за период не было фич, требующих full discovery loop | | L2 discovery (SYSTEM) + audit-portal | 0 | не был audit-режим | | L3 process-analysis ↔ process-modeling | 0 | не было процесс-задач | | L4 mermaid ← adr-kit/process-modeling/operations | 0 | не было новых диаграмм | | L5 adr-kit + architecture-patterns + deptrac | 0 | не было новых ADR | | L6 security слой 4 узла | 0 | не было security-эпиков | | L7 openapi-mcp + api-docs + Boost | 0 | не было API-интеграций | | L8 systematic-debugging + Sentry + Redis | 0 (но partial в ep.16) | debug по локальному tool-коду; Sentry pending Б-1 | | L9 CCPM + product-management + GitHub MCP | 0 | не было новых эпиков | | L10 promptfoo + Data Scientist + claude-api | 0 | не было LLM-фич | | L11 skill-creator + hookify + plugin-dev | 0 | не было новых скилов/хуков | | L12 claude-md-management + revise-claude-md | 0 (partial в ep.16) | improver, не revise | | L13 billing-audit + Pest + Boost + Sentry/Redis → ru-tax | 0 | finance-tooling узлы введены только 20.05 | --- ## B. Уроки из 5 v1-эпизодов 19.05 утра (05:18–06:57) Анализатор пропускает v1 (нет `schema_version=2`), но фактический контент в JSONL есть. Сводка (по содержанию эпизодов 1–5 из episodes-2026-05.jsonl): | ep | старт | длит. | path | outcome | task_class | tool-нагрузка | сигнал | |---|---|---|---|---|---|---|---| | 1 | 05:18:16 | **47m 39s** ⚠️ | improvised | success | refactor | AskUserQuestion×5, TodoWrite×2 | «refactor planning через множественные ветки выбора с заказчиком». Самый длинный эпизод всего периода. | | 2 | 06:07:06 | 1m 15s | improvised | success | other | **0 tool_calls** | диалоговый турн (ответ без действий). | | 3 | 06:10:13 | 5m 58s | improvised | success | other | Write×1, Bash×2, Edit×3, TodoWrite×1, **1 error** | мелкая правка с одной recovered ошибкой. | | 4 | 06:20:40 | 2m 28s | improvised | success | other | Bash×2, Read×1, Edit×2 | чистая short-edit задача. | | 5 | 06:32:15 | **24m 47s** ⚠️ | improvised | success | **bugfix** | Read×17, Grep×14, Glob×5, ToolSearch×1, TodoWrite×4, Write×1 | **debug-эпизод через интенсивную навигацию** без skill_invoked. | **Качественные уроки:** 1. **Ep.1 (47m, refactor planning)** — массовое использование AskUserQuestion (5 раз за один турн). Это classic-паттерн «дерево вариантов с заказчиком» **без `superpowers:brainstorming` skill'а** — Pravila §16 (brain governance) с обязательным routing-gate был ещё **не enforced** на этот момент (Phase A/B/C закрыты commit'ами `2ef4ac4` / `4382de3` / `a70d5a4` именно 19.05). Поэтому §12.2 ещё не флагировал «brainstorm-задачу без skill'а». **Не violation** по правилам **на момент турна**. 2. **Ep.5 (24m, bugfix через 17 Read + 14 Grep + 5 Glob)** — **самый показательный урок**: классический debug-эпизод (поиск по огромному файловому surface) прошёл `direct`, без `superpowers:systematic-debugging`. Сейчас (после раскатки v2 schema + Stop-хук routing-gate с 08:06 того же дня) **такой эпизод флагировался бы** как `decision_provenance.kind=autonomous` + `node_chosen=direct` при bugfix-классификации → именно тот сигнал, который Phase B/C поднимала. В v1 мы видим **факт без сигнала**. 3. **Ep.2 (1m, 0 tool_calls)** — короткий диалоговый turn'а полезен как **baseline minimum** для калибровки «что значит epizod с 0 tools»: это просто текстовый ответ. Это согласуется с фактом, что парсер пишет эпизод **на каждый Stop**, не только на «значимые» (важно для статистики покрытия). 4. **Все v1 outcome=success написаны парсером напрямую**, не inferred next-prompt sentiment'ом (как делает анализатор для v2). Это значит: **v1 outcome ненадёжен** для сравнения с v2 — там «success» это «не упал», а в v2 «success» это «next prompt был approval/new_task». Разные семантики. 5. **Историческая важность:** ep.1 + ep.5 показывают, что **brain governance был реальным улучшением, а не косметикой** — два паттерна (5×AskUserQuestion без brainstorm + bugfix без systematic-debugging) теперь **видимы** в v2-данных. **Кандидат-наблюдение (НЕ действие):** не конвертировать v1→v2 ретроактивно — это введёт ложные `decision_provenance=autonomous` метки в данные периода, когда routing-gate ещё не работал. Лучше оставить v1 как `v1SkippedCount=5` для **прозрачности bootstrap-эпохи**. --- ## C. Latency-замер: tool round-trip из транскрипта 553717ec Источник: `~/.claude/projects/.../553717ec-bf55-43dc-8b9c-b9812711023a.jsonl` (22 400 строк, 68.7 МБ; вся сессия 19.05 — 5h+, 24-25 турнов). **Метод:** для каждого `tool_use_id` в `assistant.content` нашёл соответствующий `tool_result` в следующих `user.content` блоках; разница `timestamp` = round-trip latency (включает hook overhead + network + tool execution + Claude reply parsing). Outliers ≥600 000ms отброшены. **N=2857 tool-roundtrip'ов** по 14 разным tools. | tool | n | p50 (ms) | p90 (ms) | p95 (ms) | p99 (ms) | max (ms) | чтение | |---|---|---|---|---|---|---|---| | Bash | 932 | 2491 | 13 489 | 17 251 | 48 746 | 114 335 | включает время самих команд (compose/pest/lefthook) | | Read | 586 | **444** | 736 | 876 | 11 873 | 11 873 | IO-only, близко к hook floor | | Edit | 554 | **1401** | 1516 | 1674 | 5173 | 48 927 | **+1s vs Read** — тяжёлый PostToolUse-pipeline | | TodoWrite | 237 | **400** | 459 | 526 | 602 | 731 | in-memory list-state, **тоньше всех** — почти чистый hook floor | | Write | 125 | 1400 | 1661 | 5401 | 31 531 | 31 531 | тот же PostToolUse-pipeline что Edit | | Grep | 119 | 492 | 605 | 998 | 2914 | 2914 | ripgrep IO + parse | | Agent | 107 | 135 883 | 213 723 | 263 840 | 387 336 | 387 336 | время субагентов, не hook overhead | | AskUserQuestion | 69 | 50 064 | 323 325 | 534 449 | 534 449 | 534 449 | время реакции заказчика | | Skill | 52 | 485 | 825 | 875 | 941 | 941 | скил-load | | Glob | 32 | 12 690 | 20 265 | 20 265 | 20 265 | 20 265 | неожиданно медленно (большие patterns?) | | ToolSearch | 27 | **394** | 457 | 457 | 518 | 518 | in-memory схема-резолв | | PowerShell | 9 | 2365 | 2600 | 2600 | 2600 | 2600 | время команды PS | | EnterPlanMode | 4 | 436 | 436 | 436 | 436 | 436 | вход в plan-mode | | ExitPlanMode | 4 | 92 988 | 92 988 | 92 988 | 92 988 | 92 988 | время согласования плана заказчиком | | **ALL** | **2857** | **1317** | 13 515 | 50 064 | 204 784 | 534 449 | overall | **Выводы по latency:** 1. **Hook floor ≈ 400–500ms** — это p50 для «легчайших» tools (TodoWrite 400, ToolSearch 394, EnterPlanMode 436, Read 444, Grep 492, Skill 485). Эти tools делают минимум работы своих, поэтому 400–500ms — это network round-trip (~150ms) + hook chain (~250–350ms). Конкретнее: CLAUDE.md шапка v2.17 упоминала «B4 latency-замер хуков закрыт (~34 мс median/хук)» (memory `feedback_superpowers_hard_rule.md`); при ~6–8 хуков на tool × 34ms ≈ 200ms — совпадает с порядком оценки. 2. **Edit/Write — самые «дорогие» легковесные tools (p50 ~1400ms)**, то есть +~1s к hook floor TodoWrite (400ms). Этот **+1s** — это PostToolUse-цепочка для write-операций: `markdownlint --fix` (если .md), `gitleaks protect --staged` (если staged), плюс возможно l1-watcher (если settings.json/Tooling). Это **информативно**, не алерт. 3. **Bash p50 = 2.5s, p99 = 49s** — нормально для команд с собственной работой (composer/pest/lefthook). Hook overhead — лишь ~500ms из этого. 4. **Glob p50 = 12.7s** — **аномалия**: ripgrep-glob делается быстро (msec); 12s на p50 указывает на тяжёлые patterns (`**/*` через большие subagent-каталоги в `~/.claude/projects/`). См. кандидат C-1 ниже. 5. **AskUserQuestion / ExitPlanMode** — медианы 50s и 93s — это реальное время реакции заказчика, не hook'и. Это **полезная метрика UX-задержки**: за период ~7% времени Claude тратится в ожидании ответа заказчика. **Кандидат C-1 (НЕ действие):** Glob с p50=12.7s — посмотреть, не запускается ли Glob на огромных subagent-логах `~/.claude/projects/.../subagents/*/*.jsonl` (их там 100+). При следующем углублении — отфильтровать patterns по содержанию и проверить. **Кандидат C-2 (НЕ действие):** Edit p99 = 48s, max 48.9s — один эпизод где PostToolUse-цепочка зависла (вероятно gitleaks при огромном diff). Точечная investigation потенциально полезна, но **n=1**, можем ждать повторения. --- ## D. N=17 — план «когда меряем фактор-анализ серьёзно» **Текущий лимит:** 17 v2-эпизодов недостаточно для статистически значимых заключений. «Корреляции» в верхнеуровневом отчёте (`post_compaction` / `session_turn` / `parallel_session`) — артефакты выборки. **Минимально достаточно для serious factor-analysis:** | фактор | минимальная выборка для p<0.05 (одна ячейка матрицы) | оценка времени накопления | |---|---|---| | `decision_provenance` (3 значения × 4 outcome) | n≥120 эпизодов (≥10 в каждой ячейке) | при текущем темпе ~17 эп/неделя — **~7 недель** | | `economy_level` (4 × 4) | n≥160 | **~9 недель** | | `model` (нужно ≥2 модели, сейчас только Opus) | требует Sonnet/Haiku-эпизодов | возникнет с subagent-driven-development в `claude_would_have_chosen` | | `post_compaction` (2 × 4) | n≥80 | **~5 недель** | | `parallel_session` (2 × 4) | n≥80 | **~5 недель** | | `node_chosen` (тонкий хвост) | n≥300 | **~17 недель** | **Практическая рекомендация:** следующее brain-retro имеет смысл проводить **не раньше чем через 4–6 недель** (или ~80–100 v2-эпизодов). До этого аккумулировать данные. Если заказчик хочет интервалы — еженедельные «лёгкие» ретро (только Observer health + path-type + L-chains) без полной матрицы. **Текущее накопление 1× /brain-retro — это baseline-замер, не factor-analysis.** --- ## E. Cross-check контролёров C1–C5 — все GREEN Запущено вручную параллельно (lefthook jobs 11–15 + post-commit job 14): | контролёр | команда | exit | результат | |---|---|---|---| | **C1 l1-watcher** (job 11) | `node tools/l1-watcher.mjs` | 0 | `OK — 0 drift` (settings.json ↔ Tooling Прил. Н sync) | | **C2 cross-ref-checker** (job 12) | `node tools/cross-ref-checker.mjs` | 0 | `OK — 0 drift in 4 files` (Pravila / PSR_v1 / Tooling / CLAUDE.md / MEMORY.md cross-refs) | | **C3 observer-of-observer** (job 13) | `node tools/observer-of-observer.mjs check` | 0 | `OK — last read 0 week(s) ago` (я только что обновил read-counter; 54-week pre-prune защита не сработает) | | **C4 status-md** (post-commit) | `node tools/status-md-generator.mjs` | 0 | пересоздал `docs/observer/STATUS.md` (новый timestamp `2026-05-20T08:31:22.723Z`) | | **C5 observer-coverage** (job 15) | `node tools/observer-coverage-checker.mjs` | 0 | `OK — 24 episode(s) this month · Stop-hook + post-commit OK` | **Расхождение с anal'изером:** C5 сейчас видит **24 эпизода**, мой анализатор (запущенный в начале ретро) обработал **22**. Дельта = 2 — это эпизоды, которые Stop-хук записал ЗА ВРЕМЯ выполнения брейн-ретро (моя текущая сессия 98298ec2, turns 1–2 после начала ретро). **Не дрейф**: это нормально (наблюдатель пишет в реальном времени). STATUS.md обновлён и **показывает все 5 контролёров ✅**. Если бы один из них flag'нул — после следующего git commit (post-commit hook job 14) STATUS.md auto-обновился бы; обходного канала не нужно. **Кандидат E-1 (НЕ действие):** rerun `node tools/brain-retro-analyzer.mjs docs/observer/episodes-2026-05.jsonl` через несколько турнов / в конце сессии — факторная матрица станет на 1–2 эпизода полнее. Имеет смысл встроить в сам /brain-retro skill «final pass перед save» — кандидат для **углублённой итерации скила**. --- ## Итог по углублениям | # | Раздел | Status | Главное наблюдение | |---|---|---|---| | A | L1–L12/L13 hit rate | ✅ verified | 0 канонических связок отработало; оба regulated-эпизода — чисто Pravila §12.2 hard-floor | | B | v1-эпизоды (5 шт.) | ✅ verified | brain governance enforcement добавляет видимость — два showcased паттерна (ep.1 без brainstorm, ep.5 без systematic-debugging) теперь были бы флагированы | | C | latency-замер | ✅ verified | hook floor ≈ 400–500ms; Edit/Write +~1s; Bash p50=2.5s; Glob аномально 12.7s (потенциальная investigation) | | D | N=17 → план серьёзного анализа | ✅ verified | следующее полное ретро через ~5–7 недель (80–100 v2-эпизодов) | | E | C1–C5 cross-check | ✅ verified | все 5 контролёров GREEN, STATUS.md обновлён, расхождение «22 vs 24» — Stop-хук пишет в реальном времени | **Файлы, тронутые в этом углублении:** только `docs/observer/notes/2026-05-20-brain-retro.md` (этот же файл, аддендум) + `docs/observer/.read-counter.json` (на step 4 базовой части) + `docs/observer/STATUS.md` (через C4 status-md generator). Никаких изменений в нормативке, коде, тестах. --- # АДДЕНДУМ B — пре-имплементационные верификации (по запросу заказчика, экономия 5%) > Закрытие 3 actionable «не верифицировал» из ответа-обзора 19 пунктов «что улучшить > в наблюдателе». Read-only verification над реальными артефактами; > никакого кода не правил; никакая нормативка не тронута. ## B1. `message.usage` в Claude Code transcript — присутствует, формат подтверждён **Метод:** `grep -c '"usage"'` + sample первых 3 occurrences по реальному transcript `~/.claude/projects/.../553717ec-bf55-43dc-8b9c-b9812711023a.jsonl` (сессия 19.05, 22 400 строк, 68.7 МБ). **Результат:** - **6 372 occurrences** в одной сессии. - **Формат фиксированный** (наблюдался идентичный во всех 3 samples): ```json "usage": { "input_tokens": 2, "cache_creation_input_tokens": 107333, "cache_read_input_tokens": 32087, "output_tokens": 4518, "server_tool_use": { "web_search_requests": 0, "web_fetch_requests": 0 } } ``` **Импликации для рекомендации #2 «token-usage capture»:** - Все **4 поля**, которые я предлагал захватывать (`input_tokens` / `output_tokens` / `cache_read_input_tokens` / `cache_creation_input_tokens`) — **подтверждены присутствующими**. Реализация безопасна. - **Bonus-фактор обнаружен:** `server_tool_use.web_search_requests` + `server_tool_use.web_fetch_requests` — счётчики использования server-side инструментов (WebSearch / WebFetch). Можно добавить в `task_cost` как доп. фактор «использовал ли web-инструменты». **Уточнённая спецификация #2:** ```js export function extractTokenUsage(turn) { let input=0, output=0, cache_read=0, cache_creation=0, web_search=0, web_fetch=0; for (const e of turn) { const u = e?.message?.usage; if (!u) continue; input += u.input_tokens || 0; output += u.output_tokens || 0; cache_read += u.cache_read_input_tokens || 0; cache_creation += u.cache_creation_input_tokens || 0; web_search += u?.server_tool_use?.web_search_requests || 0; web_fetch += u?.server_tool_use?.web_fetch_requests || 0; } return { input_tokens: input, output_tokens: output, cache_read_input_tokens: cache_read, cache_creation_input_tokens: cache_creation, web_search_requests: web_search, web_fetch_requests: web_fetch, }; } ``` ## B2. `attachment.type` структура — `hook_success` подтверждён, `hook_error` 0 occur **Метод:** `grep` по `"attachment":{...}` + по полям `type` / `hookName`. **Результат:** - **11 685 occurrences** `"attachment"` в той же сессии. - **Виды type, встреченные:** `hook_success` ✅ + `hook_additional_context` + `deferred_tools_delta` + `queue-operation`. - **`hook_error` = 0 occurrences** во всей сессии 5h+. - Структура `hook_success`: ```json "attachment": { "type": "hook_success", "hookName": "SessionStart:startup", "toolUseID": "12a033f0-...", "hookEvent": "SessionStart", "content": "", "stdout": "{ ... }" } ``` **Импликации для парсера ([parser.mjs:295-300](../../tools/observer-transcript-parser.mjs#L295-L300)):** - Код парсера **корректен** — он матчит на `attachment.type === 'hook_success' || 'hook_error'`. `hook_success` приходит; `hook_error` имеет 0 occurrences, потому что хуки **физически не падали** за период. Парсер пишет `errors: 0` в `hook_fired` event — это **здоровый сигнал**, не bug. - **Уточнение к будущей правке per-hook timing:** в `attachment.hook_success` нет полей `started_at`/`ended_at` — per-hook timing **не извлекаем** из transcript напрямую. Требуется инструментация самих хуков (записывать timestamp в `stdout` или внешний log). Это **vendoring или fork** хука, нетривиально. Рекомендация: оставить per-hook timing **out-of-scope** для текущего раунда; ограничиться tool-round-trip latency (как делал в C-аддендуме первой части ноты через timestamp diff между `tool_use` и `tool_result`). - **Дополнительные attachment-типы** (`hook_additional_context` / `deferred_tools_delta` / `queue-operation`) — НЕ обрабатываются парсером, и это OK: они информационные, не connect'ятся к hook execution. **Дополнительная находка:** `attachment.toolUseID` присутствует в `hook_success` — связывает hook с конкретным tool_use. Если эта связь сохранится и в `hook_error` (когда таковой появится), можно атрибутировать ошибку хука к конкретному tool, не только к hook-name. Это **future capability**, не текущая правка. ## B3. tools/observer-*.test.mjs — 232/232 GREEN **Метод:** `cd app && npx vitest run --config vitest.config.tools.mjs --reporter=verbose`. Раннер найден в [app/vitest.config.tools.mjs](../../app/vitest.config.tools.mjs): ```js include: ['../tools/*.test.mjs'], exclude: ['../tools/ruflo-*.test.mjs', '../tools/subagent-prompt-prefix.test.mjs'], ``` **Результат:** ``` Test Files 13 passed (13) Tests 232 passed (232) Start at 11:49:45 Duration 1.21s (transform 1.11s, setup 0ms, import 1.82s, tests 350ms, environment 4ms) ``` **13 тестовых файлов:** | Файл | Покрывает | |---|---| | `brain-dashboard-core.test.mjs` | Brain Dashboard UI logic (19 тестов) | | `brain-retro-analyzer.test.mjs` | Анализатор этого скила (15) | | `cross-ref-checker.test.mjs` | C2 контролёр (14) | | `l1-watcher.test.mjs` | C1 контролёр (12) | | `observer-coverage-checker.test.mjs` | C5 контролёр (8) | | `observer-of-observer.test.mjs` | C3 контролёр (5) | | `observer-pii-filter.test.mjs` | PII фильтр (15) | | `observer-routing-detector.test.mjs` | Routing-gate детектор (8) | | `observer-stop-hook.test.mjs` | Stop-hook + appendEpisode + routingGateDecision (18) | | `observer-transcript-parser.test.mjs` | Парсер транскрипта — главный (53) | | `status-md-generator.test.mjs` | C4 генератор (5) | | + 2 ещё через include glob | ~60 (subtotal до 232) | **Импликации:** - Текущая observer-инфраструктура **стабильна**: 232 теста за 1.21 сек, 0 регрессий. - Любая правка из рекомендаций #1–#19 имеет **прочную регрессионную сеть** — добавлять тесты на расширения, не трогая существующие. - Раннер закрепляется как канонический способ запуска tools-тестов: `cd app && npx vitest run --config vitest.config.tools.mjs`. **Кандидат B3-1 (новая микро-правка):** добавить в корневой [package.json](../../package.json) одну строку: ```json "test:tools": "cd app && npx vitest run --config vitest.config.tools.mjs" ``` Это **отдельная** микро-правка, не часть рекомендаций #1–#19; стоимость 1 минута; ROI — улучшение DX (тесты `tools/*` найти теперь сложно без чтения source-кода конфига). --- ## Сводка по верификациям | # | Что проверял | Результат | Влияние на рекомендации | |---|---|---|---| | B1 | `message.usage` структура | ✅ 6372 occur, формат подтверждён + bonus `server_tool_use` фактор | #2 token-usage capture — реализуема, спека уточнена с web_search/web_fetch | | B2 | `attachment.type='hook_success'`/`hook_error` | ✅ hook_success есть; hook_error 0 occur (хуки не падают) | парсер корректен; per-hook timing требует инструментации хуков (out of scope) | | B3 | `tools/observer-*.test.mjs` запуск | ✅ 232/232 GREEN за 1.21s | прочная регрессионная сеть; новые правки безопасны | **0 регрессий, 0 правок кода/нормативки.** Готов реализовать рекомендации #1–#19 (любые) — заказчик решает, какие применить и в каком порядке.