ADR 0009 — Agente PO, backlog (epics/stories/tasks) e rastreabilidade
- Status: aceito
- Data: 2026-07-24
- Fase: 3b (sessĂŁo 2)
Contexto
A 3b sessĂŁo 1 entregou o Criativo conversacional (emite business_rule,
consolida product_brief e oferece handoff ao PO — handoffs com status
offered, regra de ativação que exige accepted). Esta sessão fecha o ciclo:
o usuário aceita o handoff, o PO é ativado, consome o brief + as regras
e produz o backlog (Ă©picos → histĂłrias → tarefas) com DoD/DoR e vĂnculo
obrigatório a regras de negócio, mantendo rastreabilidade regra→stories.
Decisões
1. PO como GenServer conversacional com loop de tool use por turno
O Engine.Agents.PoServer espelha o CriativoServer (GenServer por sessĂŁo,
estado + rehydration + streaming pelo canal Phoenix), mas cada turno roda um
loop bounded de tool use: despacha create_epic/create_story/create_task e
injeta o resultado (id/erro) de volta como mensagem tool, re-chamando o
modelo — assim ele encadeia (id do épico → create_story → create_task). O
Criativo nĂŁo faz isso (single-turn). Ativado pelo handoff aceito (nĂŁo por
comando do usuário), o PO faz um :kickoff no start FRESCO (lê o brief + regras
do event log e gera o backlog); restart/reativação não regeram.
2. Backlog em tabelas prĂłprias; arrays em JSONB; vĂnculo a regra por ULID
epics/stories/tasks (migração 0011). Como o projeto não usa arrays do
Postgres, RF/RNF/DoD/DoR/business_rule_ids sĂŁo jsonb ($type<string[]>).
business_rule_ids referencia session_events.id (o artefato
artifact.business_rule) por texto ULID sem FK — mesma escolha de
handoffs.artifact_id (vĂnculo lĂłgico, nĂŁo relacional). Tarefas herdam o
vĂnculo da histĂłria (derivado, nĂŁo armazenado).
3. Prontidão draft→ready validada no DOMÍNIO
domain/backlog/story-readiness.ts (assertReady → StoryNotReadyError) exige
DoD, DoR nĂŁo vazios, ≥1 RF e ≥1 regra vinculada — "validação no domĂnio, nĂŁo sĂł
no prompt". story-state-machine.ts cobre draft→ready→in_progress→done. O
create_story cria em draft e promove pra ready na mesma operação quando
a regra é satisfeita (o PO usa só as 3 ferramentas nomeadas — não há tool de
transição); TransitionStoryUseCase expõe a transição explĂcita (testada) e
serve os estados futuros.
4. Ferramentas do PO passam pela api (nunca SQL/insert direto)
create_epic/create_story/create_task sĂŁo tools :direct que chamam o
EngineApiClient → endpoints internos → use-cases com validação de domĂnio.
CreateStoryUseCase valida que cada business_rule_id referencia mesmo um
evento artifact.business_rule existente (recusa ids inventados; nada Ă©
criado). Cada criação emite backlog.* no event log (narrativa do PO).
5. Rastreabilidade regra→stories (pendência = descoberta)
domain/backlog/coverage.ts (computeCoverage, puro) + GET /projects/:id/ coverage: para cada artifact.business_rule do projeto, quais histĂłrias a
cobrem (via business_rule_ids). Regra sem cobertura é uma descoberta — a
UI a mostra em vermelho na tab Backlog. NĂvel de projeto (agrega as regras das
sessões via join em sessions).
6. Aceitar handoff ativa o PO pela regra da sessĂŁo 1
AcceptHandoffUseCase (ação do usuário): offered→accepted + handoff.accepted
→ chama ActivateAgentUseCase pro toAgent. A regra de ativação (que exige um
handoff accepted) agora passa exatamente por causa desta aceitação. UI: botão
"Aceitar handoff e iniciar PO" na sessĂŁo.
ConsequĂŞncias
- A tab Backlog Ă© project-level (estado local, sem rota nova), lida do poll de
GET backlog+GET coverage— reflete o PO gerando em tempo real. - O composer da sessão roteia pro agente ativo (PO tem precedência sobre o
Criativo) via
sendAgentMessage. - Testes: domĂnio (
story-readiness,story-state-machine,coverage), use-case (create-storyrecusa regra inexistente;transition-storyrejeita draft→ready sem DoD), epo_server_test(kickoff encadeia create_epic→ create_story com injeção de resultado; regra inválida vira tool-result de erro sem derrubar o loop; broadcast; rehydration).
Escopo
SĂł o PO + backlog + rastreabilidade. O Arquiteto (ADRs em docs/adr/ do repo
do projeto, module_map, validar que story referencia mĂłdulo existente) Ă© a
próxima sessão. in_progress/done e edição manual do backlog na UI ficam pra
depois (a máquina de estados já cobre).