mozak.tech Engenharia de IA Corporativa 66%

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

4.2 — Priorização Inteligente de Backlog e Construção de Roadmap (Backlog + IA)

Objetivo da Aula

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

Calcular WSJF (Weighted Shortest Job First) para priorização SAFe

Gerar sugestão de roadmap trimestral via LLM combinando RICE e MoSCoW

Usar LLM para detectar duplicatas e conflitos no backlog

Completar os 2 TODOs: calcularWSJF e sugerirRoadmap

Comparar RICE vs WSJF e quando usar cada um

Por que isso importa

RICE prioriza por impacto e esforço. WSJF (SAFe) adiciona urgência temporal — o “custo do atraso”. Uma feature que perde valor rapidamente (lançamento do concorrente, janela regulatória) deve ter prioridade maior mesmo com RICE similar a outra atemporal.

Roadmap gerado por LLM combina dados de scoring com restrições de capacidade, dependências e estratégia — o que seria horas de trabalho de PM condensado em segundos.

Conceitos Fundamentais

WSJF: Weighted Shortest Job First

WSJF = Cost of Delay / Duration (effort)



Cost of Delay = Valor do Usuário + Criticidade Temporal + Redução de Risco

Cada dimensão em escala 1-10 de Fibonacci (1, 2, 3, 5, 8, 13)

WSJF mais alto = fazer primeiro

TODO 1: calcularWSJF(item)

function calcularWSJF(item) {

  const { valor_usuario, criticidade_temporal, reducao_risco, esforco } = item

  

  if (!esforco || esforco === 0) {

    return { ...item, wsjf: null, erro: 'esforço inválido' }

  }

  

  const cost_of_delay = valor_usuario + criticidade_temporal + reducao_risco

  const wsjf = cost_of_delay / esforco

  

  return {

    ...item,

    cost_of_delay,

    wsjf: Math.round(wsjf * 10) / 10,

    interpretacao: wsjf > 10 ? 'urgente' : wsjf > 5 ? 'normal' : 'pode aguardar',

  }

}

Por que Fibonacci? Em vez de escala linear (1-10), Fibonacci (1, 2, 3, 5, 8, 13) força diferenciação: há uma diferença real entre “3” e “5”, mas não entre “7” e “8”. Reduz debates sobre diferenças marginais.

TODO 2: sugerirRoadmap(historias, client)

async function sugerirRoadmap(historias, client) {

  const prioritizados = historias

    .map(calcularWSJF)

    .filter(h => h.wsjf !== null)

    .sort((a, b) => b.wsjf - a.wsjf)

  

  const contexto = prioritizados.map((h, i) =>

    `${i+1}. ${h.titulo} [WSJF:${h.wsjf}, MoSCoW:${h.moscow || 'N/A'}]`

  ).join('\n')

  

  const response = await client.messages.create({

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

    max_tokens: 600,

    system: `Você é um PM experiente. Dado o backlog priorizado, sugira um roadmap de 3 meses (Q1, Q2, Q3) considerando:

- Must-haves sempre no Q1

- WSJF mais alto = entrega mais cedo

- Máximo de 4 itens por trimestre (capacity)

- Retorne JSON: {"Q1": [...], "Q2": [...], "Q3": [...], "backlog": [...]}`,

    messages: [{

      role: 'user',

      content: `Backlog priorizado:\n${contexto}`,

    }],

  })

  

  const texto = response.content[0].text

  const i = texto.indexOf('{'), f = texto.lastIndexOf('}') + 1

  return JSON.parse(texto.slice(i, f))

}

Aprofundamento Técnico

RICE vs WSJF: Quando Usar

Contexto

RICE

WSJF

Startup descobrindo product-market fit

Melhor

OK

Empresa com ciclos SAFe/trimestrais

OK

Melhor

Urgência temporal importa muito

Não capta

Capta

Dados de usuários disponíveis

Melhor (usa Reach)

OK

Em muitos times: use RICE para conversas internas, WSJF para programação formal de PI (Program Increment).

Detecção de Duplicatas com LLM

async function detectarDuplicatas(historias, client) {

  const titulos = historias.map((h, i) => `${i}: ${h.titulo}`).join('\n')

  

  const response = await client.messages.create({

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

    max_tokens: 400,

    messages: [{

      role: 'user',

      content: `Analise estas user stories e identifique duplicatas ou conflitos:

${titulos}

      

Retorne JSON: {"duplicatas": [[0, 3], ...], "conflitos": [[1, 5, "motivo"], ...]}`,

    }],

  })

  

  const texto = response.content[0].text

  const i = texto.indexOf('{'), f = texto.lastIndexOf('}') + 1

  return JSON.parse(texto.slice(i, f))

}

Um LLM detecta que “Adicionar filtros na lista de produtos” e “Busca avançada no catálogo” se sobrepõem — o que um simples diff de texto não detectaria.

Exemplos Anotados

Exemplo 1: WSJF com itens urgentes vs atemporais

const backlog = [

  { titulo: 'LGPD: relatório de dados do usuário', valor_usuario: 5, criticidade_temporal: 13, reducao_risco: 8, esforco: 3 },

  { titulo: 'Dashboard de analytics', valor_usuario: 8, criticidade_temporal: 2, reducao_risco: 1, esforco: 5 },

  { titulo: 'Integração com API de pagamento', valor_usuario: 13, criticidade_temporal: 5, reducao_risco: 8, esforco: 8 },

]



const scored = backlog.map(calcularWSJF).sort((a, b) => b.wsjf - a.wsjf)

// → LGPD (WSJF 8.7): urgente  ← criticidade temporal 13 eleva o score

// → Pagamento (WSJF 3.2): normal

// → Analytics (WSJF 2.2): pode aguardar

O LGPD seria prioritário mesmo tendo valor de usuário menor que pagamento — urgência temporal (deadline regulatório) domina.

Padrões e Armadilhas

Padrões

Padrão 1: Comparar dentro do mesmo sprint/PI WSJF 8.7 vs 2.2 faz sentido no mesmo backlog. Não compare WSJF entre projetos diferentes.

Padrão 2: MoSCoW como constraint sobre WSJF WSJF prioriza, MoSCoW determina o mínimo viável. Must-haves entram independente do WSJF.

Armadilhas

⚠️ Armadilha 1: esforco = 0 → divisão por zero

if (!esforco || esforco === 0) return { ...item, wsjf: null, erro: 'esforço inválido' }

⚠️ Armadilha 2: Não incluir capacidade no roadmap Um Q1 com 10 itens de alta prioridade e um time de 3 devs é impossí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 — calcularWSJF(item): cost_of_delay = valor_usuario + criticidade_temporal + reducao_risco; wsjf = cost_of_delay / esforco

TODO 2 — sugerirRoadmap(historias, client): ordene por WSJF, passe para LLM com instrução de máximo 4 itens por trimestre, parse JSON resultado.

Agora você está pronto para o lab.