Перейти к основному содержимому

ADR 0194 — Одобрение плана Dev Lead активирует выполнение, а задача получает модуль, который он назначает

Статус​

Accepted. 2026-10-01 (AT-263 и AT-274, эпик EP-030, раунд 36; решения владельца от 01.10: "a ativação da execução passa a ser o APROVAR do plano do Dev Lead; aceitar o handoff do Dev Lead só o traz para planejar" и "quem atribui o módulo da tarefa é o Dev Lead, ao montar o plano de execução; só o dev daquele módulo a pega"). Пересматривает, не редактируя их, ADR 0069 (условное слияние принятия с активацией, RN-161) и ту часть ADR 0086, которая говорила, что у propose_execution_plan нет конвейера выполнения. Сохраняет ADR 0165 (репозиторий рождается при принятии к Arquiteto, принятие к Dev Lead — вторая дверь, а execution/activate без репозитория — 409) и ADR 0061 (execution.activated в консультативной сессии — 409).

Контекст​

Измерено в dev (d89f777) до изменения:

  • Кто выдаёт execution.activated — только ActivateExecutionUseCase, а он вызывается только маршрутом POST .../execution/activate. Backend принятия (AcceptHandoffUseCase) никогда ничего не активировал: он подготавливает репозиторий, когда адресат — arquiteto или dev-lead, и активирует АГЕНТА. "Активация при принятии" была на стороне WEB — handleAcceptHandoff сцеплял activateExecution, когда адресатом был dev-lead, а роль workspace была maintainer/owner (RN-161).
  • У плана не было потребителя. propose_execution_plan является proposed_action с ADR 0086, и Dev Lead приостанавливается в ожидании решения, но, будучи одобренным, он оставался approved навсегда: у ApproveActionUseCase не было ветви для этого типа, а Dev Lead читал "plano aprovado e registrado". В реальном использовании 29.09 выполнение поднялось в 06:45:01, при принятии; план пришёл в 06:47:47 и остался pending.
  • У задачи не было модуля. claimNext берёт следующую задачу todo истории ready, чей module_ids (jsonb, несколько) содержит модуль dev. При истории с двумя модулями dev-input-keyboard взял "loop de queda automática da peça", а dev-board-engine взял "mapear teclas" (сессия d7e9, seq 185/187).
  • Dev Lead не видел ни одного task_id: kickoff перечислял лишь модули и истории, взятые из журнала собственной сессии.

Решение​

  1. Принятие Dev Lead не активирует выполнение ни для какой роли. handleAcceptHandoff только принимает; AcceptHandoffUseCase не меняется (продолжает подготавливать как вторая дверь). Явная кнопка "Ativar execução" карточки (RN-137) и кнопка Visão Geral ОСТАЮТСЯ: это собственный жест того, кто решает пропустить план, а маршрут execution/activate сохраняет все отказы.
  2. Одобрение propose_execution_plan исполняет план в новом исполнителе в api — ExecuteExecutionPlanUseCase, в модуле выполнения, рядом с ExecuteParallelizationUseCase, — вызываемом ручным одобрением и автоодобрением (тип остаётся ВНЕ абсолютных пределов decide.ts, как решил ADR 0086). Он: перечитывает план против действующего module_map; записывает модуль задач; и вызывает ТОТ ЖЕ ActivateExecutionUseCase, что и кнопка, с одобрившим (или, при автоодобрении, открывшим сессию) в качестве активирующего. Без originSessionId: сессия Dev Lead — это место, где он возобновляет и повествует. Исход — executed (sessaoDeExecucao, modulos, tarefasAtribuidas) или failed (motivo), с execution.plan_applied/execution.plan_failed на временной шкале, и именно его Dev Lead читает при возобновлении.
  3. Задача получает колонку module (tasks.module text NULL, миграция 0068_modulo_da_tarefa). План несёт tarefas: [{ taskId, modulo }], валидируемый ЧИСТОЙ функцией (lerPlanoDeExecucao) против действующего module_map и задач проекта ДВАЖДЫ: при предложении (400 plano_de_execucao_invalido, без создания действия — фраза возвращается Dev Lead как ошибка инструмента) и при одобрении (карта могла измениться; отказ становится failed без записи чего-либо). Kickoff Dev Lead перечисляет ожидающие задачи backlog ПРОЕКТА (list_backlog), с task_id и модулями истории.
  4. Задачу берёт только dev модуля. claimNext и countClaimableByModule начинают использовать один предикат: t.module = $modulo ИЛИ задача без модуля, чья история имеет ровно ОДИН модуль, и он — $modulo.

Последствия​

  • Активация начинает стоить одобрения валидного плана, а план валиден, только если КАЖДАЯ упомянутая задача назначена модулю module_map. Dev Lead, который не может собрать tarefas (пустой backlog, задачи в другом проекте), ничего не активирует новым путём; явная кнопка остаётся выходом и объявлена таковым.
  • Мост для задачи без модуля намеренный и узкий. Без него тот, кто активирует через Visão Geral без плана, не имел бы ни одной доступной задачи; с ним, ограниченным историей с ОДНИМ модулем, правило "только dev этого модуля" остаётся истинным, потому что другого там нет. Задача без модуля истории с несколькими модулями стоит до следующего плана — а PO не назначает модуль, так что задача, созданная ПОСЛЕ одобренного плана, попадает в этот случай. Закрыть это (PO назначает или автоматическое перепланирование) — отдельное решение.
  • Уведомление task.became_claimable по-прежнему маршрутизируется по модулям ИСТОРИИ. Разбудить dev, который ничего не возьмёт, стоит одного запроса и никакого расхода модели; маршрутизация по модулю задачи потребовала бы трогать источники уведомления, вне области.
  • agentes по модулю остаётся информационным. Активация поднимает одного dev на модуль module_map, как прежде; больше одного на модуль — через parallelize (RN-083), с его пределом.
  • Вызов propose_action из engine остаётся на default 15 с Req для этого типа. При автоодобрении api активирует выполнение внутри того же запроса (засевает инструкции и автономию, вызывает engine); случай, превышающий 15 с, не измерялся, и если превысит, исход всё равно придёт через временную шкалу, даже если tool-result сообщит об ошибке транспорта.
  • Экран не переходит к сессии выполнения после одобрения плана (RN-634 делала это в кнопке): одобрение принадлежит ApprovalCard, другому направлению. Dev Lead говорит, в какой сессии поднялось выполнение.