Spec-driven development: por que a IA gera o código errado mesmo com a spec pronta?

Spec pronta e código errado é o cenário mais frustrante do spec-driven development, e quase nunca a culpa é do modelo: o agente só preencheu sozinho o que a frase deixou em aberto. Este post cataloga os 4 defeitos que mais causam isso (ambiguidade, escopo implícito, restrição técnica ausente e decisão em aberto), mostra o trecho reescrito de cada um e fecha com a rotina de validação: marcar as lacunas com [NEEDS CLARIFICATION], reescrever em padrão EARS, guardar as regras inegociáveis na constituição e rodar clarify e analyze antes de mandar implementar 🙂
Tu escreveu a spec, o agente seguiu o que estava lá, e mesmo assim o código saiu diferente do que tinha na tua cabeça
Fala aí, beleza? Essa cena é bem mais comum do que parece, e na maioria das vezes o problema não é o modelo
O agente não desobedeceu: ele preencheu sozinho o buraco que a spec deixou
E ele vai preencher SEMPRE, porque é isso que um LLM faz quando falta informação: escolhe a opção mais plausível e segue em frente, sem avisar
Aqui o post é um diagnóstico dos defeitos de escrita que transformam spec-driven development em retrabalho: quatro padrões de frase que sabotam a implementação, o trecho reescrito de cada um e a rotina de validação antes de pedir o código
Se tu ainda tá se situando no conceito, vale ler antes o que é spec-driven development e voltar pra cá com a tua spec na mão
O que você precisa antes de diagnosticar sua spec
São três coisas, e a terceira é opcional:
- Uma spec já escrita, mesmo torta, mesmo pela metade (o diagnóstico é sobre o texto que existe, não sobre um template em branco)
- Um agente de código integrado ao teu ambiente, seja CLI ou IDE
- Opcionalmente, o Spec Kit, o toolkit open source publicado pelo GitHub pra guiar agentes por um processo estruturado
O Spec Kit vive no repositório github/spec-kit, mantido pelo GitHub, com documentação em github.github.com/spec-kit
Se tu só quer experimentar sem instalar nada, dá pra rodar avulso via uvx apontando pro repositório:
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
Pra usar o diretório atual em vez de criar pasta nova, troca o nome do projeto por um ponto, mantendo o mesmo uvx na frente:
uvx --from git+https://github.com/github/spec-kit.git specify init .
Já se tu quer o CLI sempre à mão, a instalação persistente é essa:
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
Roda com o teu agente? Provavelmente sim: o Claude Code está entre as integrações oficialmente suportadas (chave claude), junto de copilot, gemini, cursor-agent, codex, windsurf, qwen, opencode, kilocode, auggie, codebuddy e q
Tome cuidado com um detalhe: as integrações de CLI exigem a ferramenta já instalada na máquina, senão o init não tem com quem conversar
Os 4 defeitos de spec que fazem a IA gerar o código errado
Cada bloco aqui segue o mesmo formato: o sintoma que tu vê no código, a frase da spec que causou aquilo, o trecho reescrito e como prevenir
Bora ver na prática?
Defeito 1: ambiguidade (o adjetivo sem critério)
Sintoma no código gerado: o agente entrega algo que tecnicamente funciona, mas tu olha e pensa "não é isso que eu queria", sem conseguir apontar a linha errada
Causa na spec: adjetivo solto, sem número e sem condição. Palavras tipo rápido, amigável, seguro, intuitivo, performático
# frase ambígua
A busca de produtos precisa ser rápida e ter uma interface amigável
"Rápida" pra ti pode ser resposta instantânea, pro modelo pode ser "não travar o navegador"
Reescrita com condição verificável:
# frase com critério
Quando o usuário enviar o termo de busca, o sistema deve exibir a
primeira página de resultados em até X segundos (X é o limite que
tu define pro teu projeto)
A lista deve mostrar nome, preço e imagem de cada produto,
ordenados por relevância
O número ali é teu, não meu: o ponto é que ele EXISTA e possa ser conferido depois
Como prevenir: régua simples, se tu não consegue imaginar um teste que prova a frase, ela ainda tá ambígua
Defeito 2: escopo implícito (o óbvio que tu não escreveu)
Sintoma no código gerado: o agente inventa telas, campos e fluxos que ninguém pediu, ou ignora um pedaço que pra ti era parte do combo
Causa na spec: tu descreveu o que quer e presumiu que o resto vinha junto
# escopo implícito
O usuário deve poder salvar seus itens favoritos
Salvar onde? Precisa de login? Edita? Exclui? Tem limite de quantos? Aparece em alguma listagem?
O agente vai responder tudo isso sozinho, e cada resposta é uma decisão de produto que ele tomou no teu lugar
Reescrita explicitando dentro e fora:
# escopo fechado
Dentro do escopo:
- usuário autenticado salva e remove um item da lista de favoritos
- a lista de favoritos aparece em uma página própria
Fora do escopo desta tarefa:
- compartilhar a lista com outros usuários
- ordenar ou filtrar os favoritos
- notificação de mudança de preço
Como prevenir: toda spec ganha uma seção "fora do escopo". Parece burocracia, mas é a parte que mais economiza token e retrabalho
Defeito 3: restrição técnica ausente
Sintoma no código gerado: aparece uma biblioteca que tu não usa, um formato de data diferente do resto do projeto, um padrão de pasta que não é o teu
Causa na spec: nenhuma menção a stack, formato de dado ou limite, então o modelo escolhe pelo que é mais comum no treino dele
# sem restrição
Criar o endpoint que retorna o histórico de pedidos do usuário
Reescrita fixando a restrição como regra:
# com restrição
Criar o endpoint de histórico de pedidos seguindo as regras do projeto:
- acesso ao banco somente pela camada de repositório já existente
- datas sempre em ISO 8601, em UTC
- resposta paginada, nunca a lista completa
- nenhuma dependência nova sem aprovação
Como prevenir: restrição que vale pro projeto inteiro não deve ficar repetida em cada spec, e sim num lugar só. É exatamente pra isso que existe o arquivo de constituição, que a gente vê no próximo bloco
Defeito 4: decisão deixada em aberto
Esse é o mais traiçoeiro, porque a frase parece completa
Sintoma no código gerado: duas partes do sistema tratam a mesma regra de jeitos diferentes, e tu só descobre quando algo quebra na integração
Causa na spec: duas interpretações razoáveis convivendo no mesmo parágrafo
# decisão em aberto
O carrinho expira depois de um período de inatividade
Expira apagando os itens ou só liberando o estoque reservado? Conta inatividade da aba ou da conta?
Tem dois caminhos aqui: ou tu fecha a decisão na hora, ou tu marca ela de forma explícita
Os templates do Spec Kit obrigam a marcar toda ambiguidade com um marcador NEEDS CLARIFICATION (escrito entre colchetes no template), sempre no formato de pergunta específica, justamente pra impedir o comportamento típico do LLM de assumir algo plausível porém errado:
NEEDS CLARIFICATION: o carrinho expirado apaga os itens ou
apenas libera o estoque reservado?
E tem um limite que vale ouro: no máximo 3 marcadores por spec, reservados pra decisões críticas, aquelas que mudam escopo ou experiência e têm mais de uma leitura razoável
Se tu tá com onze marcadores, o problema não é ambiguidade pontual, é que a spec inteira ainda não foi pensada 😅
O checklist de completude do template ainda exige que NENHUM marcador desses continue na spec na hora de implementar
A prevenção que corta os quatro de uma vez: EARS
A notação EARS ataca a raiz dos três primeiros defeitos restringindo a própria frase a um conjunto pequeno de padrões com palavra-chave fixa
Ela foi criada por Alistair Mavin e colegas na Rolls-Royce, durante a análise de regulamentação de aeronavegabilidade pra um sistema de controle de motor a jato, e publicada na IEEE International Requirements Engineering Conference (RE’09), em 2009
Ou seja: nasceu num contexto onde requisito ambíguo custa muito caro 😀
São 5 padrões, mais um complexo que combina estado e gatilho:
| Padrão | Palavra-chave | Pra que serve |
|---|---|---|
| Ubíquo | sem gatilho | regra que vale sempre, o tempo todo |
| Dirigido a estado | While | comportamento enquanto o sistema está em certo estado |
| Dirigido a evento | When | comportamento disparado por um gatilho |
| Comportamento indesejado | If / Then | erro, exceção, entrada inválida |
| Feature opcional | Where | comportamento que só existe se a feature estiver presente |
| Complexo | combinação | estado e gatilho juntos na mesma frase |
Se tu conhece a ideia de escrever critério de aceite antes do código, EARS é a versão disciplinada disso: a palavra-chave te obriga a dizer QUANDO a regra vale
O Kiro, a IDE agêntica da AWS construída em torno de spec-driven development, usa justamente EARS pra converter o teu prompt em um documento formal de requisitos na etapa de requirements
Documentação oficial da notação pra quem quiser se aprofundar nos padrões
Como reescrever a spec e validar antes de mandar implementar
Agora a rotina, aplicando o catálogo em ordem
- Releia a spec caçando os 4 defeitos e marque cada lacuna crítica com o marcador
NEEDS CLARIFICATIONseguido da pergunta específica, respeitando o teto de 3
O erro comum deste passo: marcar tudo que gera dúvida. O marcador é pra decisão que muda escopo ou experiência, não pra detalhe de implementação que tu resolve numa linha
- Reescreva as frases vagas em padrão EARS, uma por uma, começando pelas que descrevem comportamento do usuário
O erro comum deste passo: trocar o adjetivo por outro adjetivo ("rápida" virando "eficiente") em vez de colocar gatilho e critério
- Mova as regras inegociáveis do projeto pra constituição, no caminho padrão
.specify/memory/constitution.md
A estrutura .specify/ criada pelo init traz ainda scripts/, specs/ e a pasta templates/ com spec-template.md, plan-template.md e tasks-template.md
O erro comum deste passo: repetir a mesma restrição de stack em toda spec nova, e aí um dia tu esquece de repetir e o agente escolhe sozinho
- Rode o comando de clarificação, que é a etapa opcional entre specify e plan:
/speckit.clarify
Ele existe exatamente pra atacar áreas subespecificadas: o agente lê a spec, faz perguntas dirigidas sobre as ambiguidades e grava as respostas de volta na própria spec
O erro comum deste passo: responder as perguntas no chat e achar que acabou. O valor tá na resposta ficar gravada no documento, não na conversa
- Rode a análise dos artefatos, que é somente leitura e não altera arquivo nenhum:
/speckit.analyze
Ela revisa em busca de inconsistências, ambiguidades e lacunas de cobertura
O erro comum deste passo: pular ela por pressa, justo quando ela é a etapa mais barata do fluxo inteiro (read-only, zero risco)
- Só então siga pro resto do fluxo, que é todo dirigido por comandos de barra no formato
/speckit.<comando>:constitution,specify,clarify,plan,checklist,tasks,analyze,implementeconverge
O erro comum deste passo: mandar implementar com marcador de clarificação ainda vivo no texto. Faz a checagem final: se sobrou um NEEDS CLARIFICATION na spec, o agente vai decidir por ti
- Não usa Spec Kit? Dá pra fazer o mesmo diagnóstico com o modo de planejamento somente leitura do Claude Code, em que ele lê arquivos e responde perguntas sem alterar nada até tu aprovar
Tu entra apertando Shift+Tab até a barra de status mostrar o modo plano, ou já começa a sessão assim:
claude --permission-mode plan
Nesse modo o Claude pode usar o AskUserQuestion pra esclarecer requisitos antes de fechar o plano, que é a mesma função do clarify: te obrigar a decidir antes de virar código
O erro comum deste passo: aprovar o plano no automático, sem ler. O plano é a última tela onde o erro ainda é barato
E se o teu ambiente é outro, o raciocínio não muda: a ideia de escrever a spec antes do código vale igual no Cursor
O que muda na prática quando a spec fecha as lacunas
No vídeo do canal eu montei o SDD na mão, com três documentos, em vez de usar framework pronto
O terceiro documento é o de tarefas: a ordem de execução que faz sentido pela perspectiva de uso, não uma lista solta
Eu ordenei começando pelo setup inicial (criar pastas, instalar bibliotecas), depois autenticação por ser complexa e vital, depois a função central do produto, e só então as partes que dependem de login. No fim eu costumo reservar uma tarefa de polimento pra aparar as arestas
O projeto foi um gerador de QR Code: sem login gera e baixa o QR Code (texto, wi-fi, contato), com login salva, gerencia e vê os anteriores numa dashboard
Escolhi de propósito uma stack que as IAs dominam: Next, TypeScript, Prisma e SQLite pra não precisar de setup de banco, mais a camada de estilização (e sim, num cenário real aquele SQLite teria que virar Postgres)
E aqui vem a parte que interessa pro assunto deste post
Com a decisão já fechada no documento, a tarefa de autenticação levou cerca de 2 minutos pra IA implementar
Depois foi só subir o servidor local, que abriu na porta 3002, e testar na mão: gerei o QR Code, baixei o PNG, escaneei e caiu no site certo. Testei o login e confirmei que estava autenticado
Os prompts de execução viraram uma coisa curta e repetitiva: executa a tarefa X, segue o documento de design, me avisa quando terminar
Percebe o deslocamento? O tempo saiu da execução e foi pro planejamento
Tu gasta mais na escrita do requisito, e em troca as etapas seguintes ficam previsíveis e sequenciais, sem precisar caprichar no prompt a cada rodada. Eu até agrupei tarefas relacionadas na execução (o CRUD de salvar QR Codes junto da dashboard) em vez de rodar uma a uma, e o ritmo foi acelerando conforme avançava
Pra ver o método rodando do zero antes de aplicar o diagnóstico na tua spec, o vídeo mostra o fluxo completo:
Quanto rigor a sua spec precisa ter?
Nem toda tarefa merece o mesmo nível de spec, e essa é a pergunta que quase ninguém faz
Birgitta Böckeler, da Thoughtworks, analisou Kiro, Spec Kit e Tessl no site do Martin Fowler e chegou numa leitura que ajuda demais aqui: spec-driven development não é uma prática única, é uma escada de ambição em três níveis
| Nível | O que a spec é | Onde o defeito dói mais |
|---|---|---|
| Spec-first | a spec dirige a tarefa atual | ambiguidade e escopo implícito, porque o estrago aparece já na primeira entrega |
| Spec-anchored | a spec é mantida e a feature evolui por ela | restrição técnica ausente, porque cada rodada nova reintroduz decisão que já tinha sido tomada |
| Spec-as-source | a spec é o arquivo-fonte e o código é a saída | decisão em aberto, já que a lacuna não é um bug pontual e sim um buraco no próprio fonte |
Se tu tá no primeiro degrau, resolver ambiguidade e fechar escopo já resolve a maior parte da dor
Agora, quanto mais tu sobe na escada, mais a spec precisa ser um documento vivo e versionado, e menos ela aguenta frase solta
O Kiro leva isso ao pé da letra materializando a spec em três documentos versionados: requirements.md, design.md e tasks.md
Repara que é a mesma lógica dos três documentos que eu montei na mão, só que com a ferramenta cuidando da estrutura pra ti
Conclusão
A spec errada sai mais cara que a spec ausente, e o motivo é psicológico: ela PARECE pronta
Sem spec tu desconfia de tudo que a IA entrega
Com uma spec ambígua tu confia, aprova, e só descobre o buraco três features depois
Recapitulando os quatro defeitos: adjetivo sem critério, escopo que tu achou óbvio e não escreveu, restrição técnica que ficou na tua cabeça e decisão com duas leituras razoáveis no mesmo parágrafo
Próximo passo prático, e é rapidinho: pega a spec da tua próxima tarefa, passa os 4 defeitos nela, marca com o marcador NEEDS CLARIFICATION mais a pergunta específica o que continuar em aberto (no máximo 3, lembra) e roda a validação antes de pedir implementação
Faça o teste e compara com a última vez que tu mandou direto 😀
até o próximo post!
Perguntas frequentes
Dá pra fazer spec-driven development sem instalar nenhum toolkit?
Dá sim, o conceito é sobre a disciplina de escrever a spec antes do código, não sobre uma ferramenta específica. O Spec Kit só dá estrutura e comandos pra esse processo, mas os quatro defeitos de escrita (ambiguidade, escopo implícito, restrição ausente e decisão em aberto) valem pra qualquer spec, com ou sem toolkit.
Qual a diferença entre spec-first, spec-anchored e spec-as-source?
São os três níveis da escada de ambição descrita por Birgitta Böckeler, da Thoughtworks, em análise publicada no site do Martin Fowler. No spec-first a spec só dirige a tarefa atual, no spec-anchored ela é mantida e a feature evolui a partir dela, e no spec-as-source a spec vira o arquivo-fonte e o código passa a ser apenas a saída gerada.
O que é a notação EARS e por que ela reduz ambiguidade?
EARS (Easy Approach to Requirements Syntax) restringe cada frase de requisito a um conjunto pequeno de padrões com palavras-chave fixas, o que reduz ambiguidade. São 5 padrões: ubíquo (sem gatilho), dirigido a estado (While), dirigido a evento (When), comportamento indesejado (If/Then) e feature opcional (Where), mais um padrão complexo que combina estado e gatilho. A notação foi criada por Alistair Mavin e colegas na Rolls-Royce, durante análise de regulamentação de aeronavegabilidade, e publicada na IEEE RE’09 em 2009.
Para que serve o comando /speckit.clarify antes de rodar o /speckit.plan?
O /speckit.clarify é uma etapa opcional entre o specify e o plan feita justamente pra atacar área subespecificada: o agente lê a spec, faz perguntas dirigidas sobre os pontos ambíguos e grava as respostas de volta na própria spec. Os templates marcam cada ambiguidade com um marcador NEEDS CLARIFICATION no formato de pergunta específica, no máximo 3 por spec, e o checklist de completude exige que nenhum sobre antes de seguir pro plano.
O que fica guardado no arquivo constitution.md do Spec Kit?
É onde ficam as regras inegociáveis do projeto, tipo padrão de acesso a banco, formato de data ou proibição de dependência nova sem aprovação. O caminho é .specify/memory/constitution.md, dentro da estrutura que o init cria (junto com scripts/, specs/ e templates/), então restrição que vale pro projeto inteiro não precisa ser repetida em cada spec individual.
Dá pra usar o modo de planejamento do Claude Code pra revisar a spec antes de gerar o código?
Dá sim, e ajuda bastante nesse diagnóstico. Basta entrar com Shift+Tab até a barra de status mostrar o modo plano, ou iniciar a sessão com claude –permission-mode plan: nesse modo o Claude só lê arquivos e responde perguntas, sem alterar nada, e pode usar o AskUserQuestion pra esclarecer requisitos antes de fechar o plano.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
A spec substitui o README e a documentação do projeto?
Spec vs documentação não é escolha: veja a diferença entre planejar uma feature (spec) e documentar como o sistema funciona hoje, e quando migrar pra lá.
O que é SDD (spec-driven development) e como funciona na prática?
SDD (spec-driven development): escreva a spec antes do código e use-a como fonte única de verdade. Veja o ciclo prático com Spec Kit, Claude Code e Kiro.
Como criar uma skill de spec-driven development para reusar em todos os projetos
Uma skill de spec-driven development guarda seu processo de spec no SKILL.md: instale global (~/.claude/skills/) ou só no projeto e reutilize sempre.
