mozak.tech Engenharia de IA Corporativa 79%

Parte IV — Gestão de Projetos e Produto com Suporte de IA

4.7 — Consolidação de Métricas e Geração de Relatórios de Progresso (Status Reports)

Objetivo da Aula

Ao concluir esta aula, você será capaz de:

Consolidar métricas de múltiplos sprints em visão executiva

Implementar consolidarMetricas(sprints) calculando velocidade, tendências e desvios

Implementar gerarStatusReport(metricas, client) via LLM com tom executivo

Completar os 2 TODOs do starter

Identificar sinais de alerta automáticos em séries temporais de sprint

Por que isso importa

PMs gastam de 2 a 4 horas por semana compilando status reports de múltiplas fontes (Jira, Confluence, planilhas). LLM reduz isso para minutos. Mais importante: a consolidação automática elimina o viés de seleção — PMs tendem a reportar o que parece bem, a IA reporta o que os dados mostram.

Conceitos Fundamentais

TODO 1: consolidarMetricas(sprints)

function consolidarMetricas(sprints) {

  if (!sprints || sprints.length === 0) return null

  

  // Velocidade: pontos completados por sprint

  const velocidades = sprints.map(s => s.pontos_completados || 0)

  const velocidade_media = velocidades.reduce((a, b) => a + b, 0) / velocidades.length

  

  // Tendência: comparar última metade com primeira metade

  const metade = Math.floor(sprints.length / 2)

  const media_inicio = velocidades.slice(0, metade).reduce((a, b) => a + b, 0) / metade

  const media_fim = velocidades.slice(metade).reduce((a, b) => a + b, 0) / (sprints.length - metade)

  const tendencia = media_fim > media_inicio * 1.05 ? 'crescendo'

    : media_fim < media_inicio * 0.95 ? 'caindo'

    : 'estável'

  

  // Taxa de entrega (% de pontos planejados que foram completados)

  const taxas_entrega = sprints.map(s =>

    s.pontos_planejados > 0 ? (s.pontos_completados / s.pontos_planejados * 100) : 0

  )

  const taxa_media = taxas_entrega.reduce((a, b) => a + b, 0) / taxas_entrega.length

  

  // Sprints problemáticos (taxa < 70%)

  const sprints_criticos = sprints

    .filter((s, i) => taxas_entrega[i] < 70)

    .map(s => s.nome)

  

  // Último sprint

  const ultimo = sprints[sprints.length - 1]

  const ultima_taxa = taxas_entrega[taxas_entrega.length - 1]

  

  return {

    total_sprints: sprints.length,

    periodo: `${sprints[0].nome} → ${ultimo.nome}`,

    velocidade_media: Math.round(velocidade_media),

    tendencia_velocidade: tendencia,

    taxa_entrega_media: Math.round(taxa_media),

    ultimo_sprint: {

      nome: ultimo.nome,

      pontos_completados: ultimo.pontos_completados,

      pontos_planejados: ultimo.pontos_planejados,

      taxa_entrega: Math.round(ultima_taxa),

    },

    sprints_criticos,

    alertas: [

      ...(tendencia === 'caindo' ? ['⚠️ Velocidade em queda nos últimos sprints'] : []),

      ...(taxa_media < 80 ? ['⚠️ Taxa de entrega abaixo de 80%'] : []),

      ...(sprints_criticos.length > 0 ? [`⚠️ ${sprints_criticos.length} sprint(s) com entrega < 70%`] : []),

    ],

  }

}

TODO 2: gerarStatusReport(metricas, client)

async function gerarStatusReport(metricas, client) {

  const alertas_str = metricas.alertas.length > 0

    ? metricas.alertas.join('\n')

    : 'Nenhum alerta crítico'

  

  const response = await client.messages.create({

    model: 'claude-haiku-4-5-20251001',

    max_tokens: 600,

    system: `Você é um PM sênior gerando um status report executivo.

Tom: objetivo, direto, baseado em dados.

Estrutura: Status Geral (🟢/🟡/🔴), Destaques, Riscos e Ações, Próximos Passos.

Máximo de 3 bullets por seção.`,

    messages: [{

      role: 'user',

      content: `Métricas do período ${metricas.periodo}:

- Velocidade média: ${metricas.velocidade_media} pontos/sprint

- Tendência: ${metricas.tendencia_velocidade}

- Taxa de entrega média: ${metricas.taxa_entrega_media}%

- Último sprint: ${metricas.ultimo_sprint.nome} — ${metricas.ultimo_sprint.taxa_entrega}% de entrega



Alertas:

${alertas_str}



Gere um status report executivo para enviar ao VP de Produto.`,

    }],

  })

  

  return response.content[0].text

}

Aprofundamento Técnico

Detecção de Anomalias em Velocidade

function detectarAnomalias(sprints) {

  const velocidades = sprints.map(s => s.pontos_completados)

  const media = velocidades.reduce((a, b) => a + b, 0) / velocidades.length

  const desvio = Math.sqrt(

    velocidades.reduce((acc, v) => acc + Math.pow(v - media, 2), 0) / velocidades.length

  )

  

  return sprints.filter((s, i) =>

    Math.abs(velocidades[i] - media) > 2 * desvio

  ).map(s => ({ sprint: s.nome, pontos: s.pontos_completados, tipo: 'outlier' }))

}

Sprints com velocidade > media + 2σ ou < media - 2σ são anomalias que merecem investigação (bug crítico? crunch? sprint de refatoração?).

Exemplos Anotados

Exemplo 1: Consolidação de 6 Sprints

const sprints = [

  { nome: 'Sprint 1', pontos_completados: 32, pontos_planejados: 40 },

  { nome: 'Sprint 2', pontos_completados: 38, pontos_planejados: 40 },

  { nome: 'Sprint 3', pontos_completados: 25, pontos_planejados: 40 }, // problema

  { nome: 'Sprint 4', pontos_completados: 30, pontos_planejados: 40 },

  { nome: 'Sprint 5', pontos_completados: 28, pontos_planejados: 40 },

  { nome: 'Sprint 6', pontos_completados: 27, pontos_planejados: 40 }, // tendência caindo

]



const metricas = consolidarMetricas(sprints)

// → {

//   velocidade_media: 30,

//   tendencia_velocidade: 'caindo',  ← última metade media 28.3 vs primeira 31.7

//   taxa_entrega_media: 75,

//   sprints_criticos: ['Sprint 3'],

//   alertas: ['⚠️ Velocidade em queda', '⚠️ Taxa < 80%', '⚠️ 1 sprint(s) com entrega < 70%']

// }

Padrões e Armadilhas

Padrões

Padrão 1: Status geral baseado em alertas

const status_geral = metricas.alertas.length === 0 ? '🟢 Verde'

  : metricas.alertas.length === 1 ? '🟡 Amarelo'

  : '🔴 Vermelho'

Padrão 2: Report com benchmark histórico “Taxa de 75% está abaixo da nossa meta de 85% (Q3 passado: 82%)” — mais útil do que só o número absoluto.

Armadilhas

⚠️ Armadilha 1: Média de velocidade mascara tendência

Sprint 1: 45 pts, Sprint 2: 15 pts → média = 30 pts

Sprint 3: 28 pts, Sprint 4: 32 pts → média = 30 pts

Mesma média, situações completamente diferentes

Sempre calcular tendência além da média.

⚠️ Armadilha 2: Sprints com capacidade diferente Sprint com feriado ou dev afastado tem menos pontos — não é anomalia. Adicionar campo capacidade_normalizada se disponível.

⚗ Laboratório prático — mozak.tech
Se não for realizar o laboratório, pule para o próximo capítulo.

Ponte para o Lab

TODO 1 — consolidarMetricas(sprints): calcule velocidade média, tendência (primeira vs segunda metade), taxa de entrega e sprints críticos (<70%).

TODO 2 — gerarStatusReport(metricas, client): passe métricas e alertas para o LLM pedir formato executivo com 🟢/🟡/🔴.

Agora você está pronto para o lab.