Чему научил первый dogfooding
В Фазе 10 Brabo построил часть самого Brabo: поддержка Bitbucket и
GenericGitProvider были поставлены агентами продукта, в fork, с человеком в
роли пользователя. Это было первое реальное исполнение вне демо.
Этот документ — сбор урожая того прогона. Он существует потому, что
CLAUDE.md ссылался на него начиная с Фазы 10, а он так и не был написан, —
отсутствие, которое стоит зафиксировать и которое само является одной из
находок.
:::warning Что потерялось
Таблица наблюдений миссии (docs/missions/dogfooding-mission.md:488-490)
содержит одну-единственную заполненную строку: №1, ручной seed, записанный
до начала первой сессии. Ни один прогон не был подсчитан.
В репозитории нет числа перезапусков engine, ручных вмешательств, кликов
одобрения или стоимости на сессию. Сама миссия предупреждала
(colheita-esqueleto.md:63-68), что у restarts do engine нет никакой
записи в системе — это только человеческая пометка, и если её не сделать
вживую, она пропадает.
Поэтому всё количественное здесь отображается как не измерено, никогда
как оценка. Это правило самого сбора урожая: ни одно число не входит без
запроса, который его производит (colheita-esqueleto.md:22-24).
:::
Что было зафиксировано и является реальным
Уцелела качественная часть, и она плотная: семнадцать находок с файлом и строкой, проверенных в коде во время прогона. Из неё вышла вся Фаза 12.
До первой сессии: ручной seed
Прогон начался с вмешательства, которого не было в плане. Эксперимент шёл
против fork, и строки project_repositories и repo_bootstraps были
вставлены вручную, помеченные как сошедшиеся, чтобы продукт не пытался
возобновить bootstrap (dogfooding-mission.md:104-134).
Причина — находка №1: продукт умел только создавать репозиторий.
createRepo был безусловным, а getRepo существовал без единого вызывающего
со времён Фазы 2.
Это было первое ручное вмешательство эксперимента, и оно произошло до начала эксперимента (
:130-133).
Во время: партии
Второй структурный факт прогона — находка №10: dev agent обрабатывал одну
task и останавливался. :work запускался только при активации и при
принятии распараллеливания; ничто не возвращало агента от открытого PR к
состоянию «свободен для захвата».
Операционное последствие описано в :393-416: фаза шла партиями. Для
каждой следующей task нужно было перезапускать engine — dev agents имеют
restart: :temporary, умирают и не возвращаются — и заново активировать
исполнение. Повторная активация без перезапуска не помогала: супервизор
возвращал существующего агента, не запуская :work, и ещё создавал
осиротевшую сессию (находка №11).
Число перезапусков — не измерено. С уверенностью известно свойство: по тогдашнему устройству один перезапуск на каждую сданную task был полом, а не наблюдаемым средним.
Третье: продвижение без человеческого шага
Находка №13 была P2 в исходной классификации и позже повышена до P1. Переход
draft → ready происходил автоматически при создании;
TransitionStoryUseCase проверял и выпускал событие, но не был подключён ни к
одному маршруту — мёртвый код. Вкладка Backlog была только для чтения.
То есть PO, агент LLM, сам решал, что попадает в очередь работы dev agents, в продукте, чей объявленный принцип — окончательные полномочия пользователя.
Семнадцать находок
Сохранены дословно из миссии, с приоритетом, который они тогда получили. Те, что закрыла Фаза 12, помечены.
Из обследования до первой сессии
| # | находка | где | приор. | состояние |
|---|---|---|---|---|
| 1 | Продукт не умеет направить проект на существующий репозиторий. createRepo безусловен; getRepo существует и не вызывается ни одним use case; в DTO нет поля для externalId | provision-repository.use-case.ts:144 | P1 | закрыта — ADR 0044 |
| 2 | protectBranch в GitHub применяет enforce_admins: true + 1 ревьюера поверх существующей защиты, не читая текущее состояние, — может заблокировать ручной merge владельца | github-provider.ts:170-175 | P1 | закрыта — стала продуктовым правилом (RN-045) |
| 3 | Bootstrap создаёт и защищает ветку rc, которую политика веток Brabo (Фаза 6) не использует | bootstrap-steps.ts:94,195 | P2 | закрыта — RN-029 |
| 4 | agent_areas/agent_area_members не существуют; области, leads и участники захардкожены в двух местах, которые могут разойтись | schema.ts:781-786 | P2 | зафиксированный срез Фазы 8 |
| 5 | Шесть providers LLM Фазы 9b не вошли, а CLAUDE.md описывал Фазу 9 так, будто вошли | ADR 0042:147-156 | P2 | закрыта в Фазе 11 |
| 6 | git-providers.md утверждает, что Bitbucket и Generic «вне рамок»; CLAUDE.md помечал оба как активную фазу | docs/reference/git-providers.md:170-174 | P2 | закрыта в самой Фазе 10 |
| 7 | Комментарий git-errors.ts говорит «8 операций»; в контракте их 10 | git-errors.ts:3 | P3 | закрыта — и подсчёт стал тестом |
| 8 | Заголовок контрактной suite говорит, что её проверяет только Local; GitHub и GitLab запускают её со времён Фазы 2 | git-provider.contract.ts:12-18 | P3 | закрыта — и список вызывающих стал тестом |
Из обследования ведения
| # | находка | где | приор. | состояние |
|---|---|---|---|---|
| 9 | От Criativo нельзя отказаться. Claim требует story ready; ready требует ≥1 бизнес-правила; id проверяется по реальному событию; и только у Criativo есть emit_artifact | story-readiness.ts:46, po_server.ex:18 | P1 | открыта |
| 10 | Dev agent обрабатывает ОДНУ task и останавливается. :work запускается только при активации и при принятии распараллеливания | dev_agent_server.ex:76-91,306-327 | P1 | закрыта — ADR 0045 |
| 11 | Повторная активация исполнения не перезапускает :work и ещё создаёт лишнюю сессию без привязанных агентов | dev_agent_supervisor.ex:33-52 | P2 | закрыта — RN-053 |
| 12 | Нет ручного handoff агенту по выбору, а проверка цели из ADR 0038 так и не была реализована | SessionPage.tsx:403-407 | P2 | наполовину закрыта — проверка цели в RN-054; ручной handoff остаётся открытым |
| 13 | Нет «продвинуть в ready»: продвижение автоматическое при создании. TransitionStoryUseCase не подключён ни к одному маршруту — это мёртвый код | create-story.use-case.ts:75-78 | P2 → P1 | закрыта — ADR 0046 |
| 14 | Нет возврата PO — ни состояния, ни события, ни кнопки | — | P2 | закрыта вместе с №13 |
| 15 | Панель команды и гипотезы Psicólogo делят одну вкладку, которая является вкладкой проекта по умолчанию | ProjectOverviewTab.tsx:227-263 | P2 | закрыта — собственная вкладка Insights, со счётчиком |
| 16 | Ни один экран не суммирует одобрения по сессии; у Anamnese по требованию нет кнопки | hooks.ts:153-160 | P3 | закрыта частично — см. примечание ниже |
| 17 | Главной метрики фазы нет в event log. proposed_action.approved/.denied идут только в outbox | approve-action.use-case.ts:98 | P1 | закрыта — ADR 0048 |
:::note У находки №16 была ошибочная половина
При её закрытии проверка показала, что второе утверждение — «у Anamnese по
требованию нет кнопки» — было ложным уже тогда, когда находка была
написана: маршрут POST /projects/:projectId/anamnese/run существует
(anamnese.controller.ts:71), а кнопка «Rodar agora» находится в Настройках ›
Proficiência (ProjectSettingsTab.tsx:777), покрытая
ProficiencySection.test.tsx.
Первая половина была реальной и закрыта: вкладка Сессии начинает суммировать
предложенные действия каждой сессии, отделяя то, что было вашим кликом
(decidedBy), от того, что автоодобрила политика (resolvedPolicy). Раньше
всё бралось из usePendingActions, который требует sessionId, и три
вызывающих передавали id самой свежей сессии — решение, забытое в предыдущей
сессии, навсегда оставалось невидимым.
Запись остаётся, потому что сбор урожая не исправляют стиранием: частично ошибочная находка — это информация о том, как вёлся прогон.
:::
Два пункта вошли как запись, а не дефект, чтобы сбор урожая не принял их
за пробел: merge вне продукта (awaiting_user намеренно терминален,
RN-014 — engine даже не знает git_merge) и
отказ от QA по ключевому слову в нефункциональном требовании
(qa_lead.ex:20-28), что является объявленной эвристикой, а не NLP.
Что не было измерено
Перечислено явно, чтобы не выглядело забывчивостью:
| что | почему |
|---|---|
| перезапуски engine на task | в системе нет записи; зависело от живой человеческой пометки |
| ручные вмешательства и их причины | то же — таблица наблюдений осталась пустой начиная со строки 2 |
| клики одобрения на сессию | находка №17 объясняет: proposed_action.approved не шёл в session_events; долговременным источником был proposed_actions.decided_at, который прогон не свёл воедино. Закрыто позже ADR 0048 — метрика существует с этого момента, но не распространяется задним числом на этот прогон |
| стоимость в токенах по агенту и по provider | данные есть в token_usage, но ни один запрос не был выполнен, а база того исполнения не сохранилась |
| круги исправлений в gates | то же |
Находка №17 — самая дорогая в этом наборе, и урок — об инструментировании: главная метрика эксперимента должна быть в долговременном логе до начала эксперимента. Её там не было, и поэтому количественной половины сбора урожая не существует. Она была закрыта позже, ADR 0048, и это действует для следующего эксперимента: никакое исправление не восстановит данные, которые не были записаны.
Что Фаза 12 с этим сделала
Три находки P1 по эксплуатируемости — №1, №10 и №13 — были закрыты в Фазе 12, а доказательство того, что они умерли в одном исполнении, находится в Проверке Фазы 12.
Четвёртая P1, №17, была закрыта позже ADR 0048, вместе с D5, который ADR 0045 оставил зафиксированным.
Остальные по-прежнему открыты, перечислены выше, и ни одна не была исправлена мимоходом: исправление находки вне фазы, которая ею занимается, — это ровно то, что миссия запрещала (принцип 3).