408a44a53a
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
808 lines
60 KiB
Markdown
808 lines
60 KiB
Markdown
# 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/<x>/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` — «после `<context_compaction>`-маркера ход 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
|
||
(любые) — заказчик решает, какие применить и в каком порядке.
|