ADR 0194 — 批准 Dev Lead 的计划会激活执行,任务获得它所分配的模块
状态
已接受。 2026-10-01(AT-263 和 AT-274,史诗 EP-030,第 36 轮;所有者于 10月1日的决定:"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 的 handoff 时诞生,Dev Lead 的是第二道门,没有仓库的 execution/activate 是 409)和 ADR 0061(咨询会话中的 execution.activated 是 409)。
背景
修改之前在 dev(d89f777)中测得:
- 发出
execution.activated的只有ActivateExecutionUseCase,而它只由路由POST .../execution/activate调用。接受的后端(AcceptHandoffUseCase)从未激活任何东西:当目的地是arquiteto或dev-lead时它开通仓库,并激活 agent。“接受时激活”是 WEB 的——当目的地是dev-lead且 workspace 角色是maintainer/owner时,handleAcceptHandoff串联activateExecution(RN-161)。 - 计划没有使用者。 自 ADR 0086 起
propose_execution_plan是proposed_action,Dev Lead 挂起等待决定,但被批准后它就永远停在approved:ApproveActionUseCase没有该类型的分支,而 Dev Lead 读到的是“plano aprovado e registrado”。在 9月29日的真实使用中,执行在 06:45:01 接受时启动;计划在 06:47:47 到达,停在pending。 - 任务没有模块。
claimNext取下一个属于ready故事、且其module_ids(jsonb,多个)包含该 dev 模块的todo任务。对于一个有两个模块的故事,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 只列出模块和故事,取自它自己会话的日志。
决策
- 接受 Dev Lead 不会激活执行,对任何角色都不会。
handleAcceptHandoff只接受;AcceptHandoffUseCase不变(继续作为第二道门开通)。卡片上显式的“Ativar execução”按钮(RN-137)和概览上的保留:它们是决定跳过计划的人的独立操作,而路由execution/activate保留所有拒绝。 - 批准
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 恢复时读到的内容。 - 任务获得
module列(tasks.module text NULL,迁移0068_modulo_da_tarefa)。计划携带tarefas: [{ taskId, modulo }],由一个纯函数(lerPlanoDeExecucao)针对当前的module_map和项目的任务进行验证,两次:在提议时(400plano_de_execucao_invalido,不创建动作——这句话作为工具错误返回给 Dev Lead)以及在批准时(映射可能已经改变;拒绝变成failed,不写入任何东西)。Dev Lead 的 kickoff 列出项目 backlog 中的待处理任务(list_backlog),带task_id和故事的模块。 - 只有该模块的 dev 才会领取任务。
claimNext和countClaimableByModule开始使用同一个谓词:t.module = $modulo,或者没有模块、其故事恰好有一个模块且就是$modulo的任务。
后果
- 激活开始需要批准一个有效的计划,而只有当被引用的每个任务都分配到
module_map的一个模块时,计划才有效。无法组装tarefas的 Dev Lead(backlog 为空、任务在另一个项目中)不能通过新路径激活任何东西;显式按钮仍然是出路,并被声明为出路。 - 为没有模块的任务搭的桥是有意且狭窄的。 没有它,从概览不带计划激活的人将没有任何可领取的任务;把它限制在只有一个模块的故事上,“只有那个模块的 dev”这条规则仍然成立,因为那里没有别的模块。属于多模块故事、没有模块的任务会停着,直到下一个计划——而 PO 不分配模块,所以计划批准之后创建的任务会落入这种情况。关闭这一点(由 PO 分配,或者自动重新规划)是另一项决定。
- 提示
task.became_claimable仍按故事的模块路由。 唤醒一个不会领取任何东西的 dev 只花一次查询,不花任何模型费用;按任务的模块路由需要改动提示的发出者,超出了范围。 - 按模块的
agentes仍然只是信息性的。 激活按module_map的每个模块启动一个 dev,和以前一样;每个模块多于一个仍然通过parallelize(RN-083),带它的上限。 - 对这个类型,engine 的
propose_action调用仍使用 Req 默认的 15 秒。 自动批准时,api 在同一个请求中激活执行(播种指令和自主权,调用 engine);没有测得超过 15 秒的情况,而如果超过,即使工具结果说是传输错误,结局也会经由时间线到达。 - 批准计划后,界面不会导航到执行会话(RN-634 在按钮上这样做):批准属于
ApprovalCard,是另一条战线的。Dev Lead 会说执行是在哪个会话中启动的。