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 diferentesSempre 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.
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.