ADR 0089 — analytics e delivery-metricas viram script de relatório
- Status: Aceito
- Data: 2026-08-16
- Contexto: decisão do dono do produto de antecipar dois papéis do
modelo-alvo (
docs/fluxo.yml) sem esperar o gatilho orgânico - Peça irmã: ADR 0085
(
docs/fluxo.yml); precedente direto de FORMA:apps/api/scripts/medir-execucao.ts(Fase 13b)
Contexto
docs/fluxo.yml já descrevia dois papéis do modelo-alvo como
status: proposto, cada um com o critério de separação que faltava para
virarem active já escrito:
analytics(Analytics Engineer, métrica de PRODUTO) — "absorvido pormedicao(que só cobre métrica de EXECUÇÃO)", com o critério "o dia em quemetricas-de-produtovirar entrada obrigatória do PO";delivery-metricas(Delivery Manager, fluxo — DORA) — "absorvido pormedicao(parcialmente)", com o critério "nunca vira agente; vira RELATÓRIO domedicao(lead time, deployment frequency, MTTR, change failure rate extraídos do event log +gates.yml)".
Nenhum dos dois gatilhos disparou organicamente. O dono do produto decidiu
antecipar a construção mesmo assim: o funil sessão → commit → PR → merge e
uma fatia real de DORA (lead time, deployment frequency) já são
extraíveis do dado que o produto já grava — proposed_actions.execution_result
para as três ações git que o dev agent produz
(apps/api/src/domain/git/git-action-execution-result.ts) e
docs/gates.yml para o gate backmerge. Esperar o gatilho orgânico
adiaria um relatório que já é possível.
Decisão
Os dois papéis viram status: active em docs/fluxo.yml, e o que os
materializa é UM SCRIPT só — apps/api/scripts/analise-funil.ts
(pnpm --filter api analise:funil -- --projeto <uuid> [--json]) — no
MESMO formato de apps/api/scripts/medir-execucao.ts:
NestFactory.createApplicationContext(AppModule), argumento
--projeto <uuid> obrigatório, leitura pura via Drizzle, zero escrita no
banco, saída Markdown por padrão e --json para consumo programático.
Isto não é uma feature nova de produto: é a forma que o próprio
docs/fluxo.yml já prescrevia para os dois papéis, só que construída
antes do gatilho previsto. Nenhum GenServer, nenhum agente de LLM, nenhuma
rota HTTP nova.
O que o script mede DE VERDADE
- Funil real (
calcularFunil): quantas sessões produziram pelo menos umgit_commit, umapr_opene umgit_mergeexecuted, e a taxa de conversão entre etapas consecutivas. Conta SESSÃO, não ação. - Lead time real (
calcularLeadTimes): do primeirogit_commitexecutedao primeirogit_mergeexecutedda mesma sessão, usandoupdated_at— o instante em queExecuteGitActionUseCasegravou oexecution_resultde verdade, não quando a ação foi proposta. - Deployment frequency real (
deploymentFrequencyPorDia):git_mergeexecutedcujotargetBranchestá emPROTECTED_BRANCHES, agrupado por dia. Cruza por REFERÊNCIA com o gatebackmerge(docs/gates.yml) — a evidência dele é CI (.release/gate.json), fora do alcance de um script que só lê o banco, então não há junção de dado nenhuma, só o mesmo recorte de branch.
O que o script DECLARA ausente, e por quê isso não é "dado que falta"
Três métricas ficam numa seção "Não medido, de propósito" da saída, e a decisão de mantê-las assim é permanente enquanto as pré-condições abaixo não mudarem — não é lacuna a fechar na próxima rodada:
- Funil de produto completo (ideação → commit).
sessionsnão temstoryId— RN-230 já declara essa lacuna na aba Criativo (apps/web/src/routes/ProjectSessionsTab.tsx). Fechá-la exigiria schema novo (coluna nova, possivelmente migration emsessionsou tabela de vínculo), fora de escopo desta frente por princípio: nenhuma migration nesta rodada. - Evidência de adoção por feature. Diferente da primeira, esta não é dado que falta COLETAR: é uma capacidade que o produto não tem CAMINHO nenhum para ter hoje. O Brabo não instrumenta os projetos que ele CONSTRÓI — não existe pipeline de telemetria de uso saindo do código gerado, nem decisão de produto sobre como ele existiria. Declarar "ausente" aqui seguiu o mesmo princípio do ADR 0042 para nota de modelo e do ADR 0077 (RN-210) para ranking "ideal": nunca aproximar com um número que pareceria real.
- MTTR e change failure rate. As duas exigem sinal de INCIDENTE de
produção real, a mesma dependência que
docs/fluxo.ymljá registra para os papéissecops-runtime/platform(status: proposto/planned, ativação sincronizada comDEPLOY_ENABLED). É trabalho de outra frente, não desta.
Consequências
docs/fluxo.yml:analyticsedelivery-metricassaem destatus: propostoparastatus: active, comsaidas_alvoreescrito parasaidas(o que é real hoje) mais um campolacunasexplícito (o que continuastatus: lacuna, sem apagar a declaração).apps/api/package.json: nova entrada"analise:funil".- Nenhuma migration, nenhuma rota HTTP nova, nenhuma tela nova.
- RN-320..322 em
docs/business-rules.mdcobrem a forma do script (RN-320), a semântica do funil e do lead time (RN-321), e a deployment frequency mais as três ausências declaradas (RN-322).
Alternativas consideradas
Esperar o gatilho orgânico de cada papel. Era o plano-padrão do
docs/fluxo.yml e continua sendo o comportamento default do modelo de
time para os outros papéis proposto. Recusada aqui só porque o dono do
produto decidiu explicitamente antecipar — não é precedente para
antecipar os demais papéis proposto sem decisão equivalente.
Um agente analytics de LLM lendo o banco e narrando o funil.
Recusada pelo próprio critério de separação que docs/fluxo.yml já
declarava para delivery-metricas ("nunca vira agente") e que esta
decisão estende a analytics: o relatório é determinístico — soma,
agrupa, filtra por status — e não precisa de um modelo para interpretá-lo.
Um agente aqui seria custo de LLM sem ganho de informação.
Aproximar as três métricas ausentes com um proxy (ex.: contar
chat.message como proxy de "uso", ou tempo até o próximo commit como
proxy de MTTR). Recusada: um proxy que se parece com a métrica real e não
é ela é o erro que o ADR 0042 já nomeou para nota de modelo — melhor "—"
com o motivo escrito do que um número que ensina errado.
Referências
docs/fluxo.yml(blocosid: analytics,id: delivery-metricas)apps/api/scripts/analise-funil.ts/apps/api/scripts/medir-execucao.ts(precedente de forma, Fase 13b)apps/api/src/domain/git/git-action-execution-result.tsdocs/gates.yml(gatebackmerge)- RN-230 — a lacuna ideação → commit, já declarada na aba Criativo
- ADR 0042 — o princípio de nunca fingir dado que não existe
- ADR 0077 — a mesma recusa aplicada a "modelo ideal"