Engenharia de Specs
Como escrever Live Specs eficazes que produzam altas Spec-to-Code Ratios e minimizem a intervenção do agente.
Visão Geral
Engenharia de Specs é a disciplina de escrever documentos Live Spec que agentes podem executar com intervenção mínima. Uma spec bem projetada produz uma alta Spec To Code Ratio — a saída do agente segue fielmente a especificação em vez de improvisar. Uma spec mal projetada produz alucinações, casos de borda ignorados e loops, independentemente de quão capaz o modelo seja.
Este padrão fornece uma metodologia estruturada para a criação de specs. Ele move as equipes de "escrever alguns requisitos e esperar que o agente entenda" para um processo repetível: começar por critérios de aceitação executáveis, decompor em comportamentos testáveis, anexar Golden Samples e restrições arquiteturais, e iterar com base em resultados mensurados. O Context Architect é o responsável por este processo, mas cada engenheiro que escreve specs se beneficia da metodologia.
A engenharia de specs é a atividade de maior alavancagem em um fluxo de trabalho de desenvolvimento agentic. Um investimento de 30 minutos em uma spec precisa economiza horas de tentativas do agente, escalonamentos de Rescue Mission e correção humana. Equipes que medem a Spec To Code Ratio descobrem consistentemente que a qualidade da spec — não a seleção do modelo, nem truques de engenharia de prompt — é o fator dominante na qualidade da saída do agente.
Problema
A maioria das equipes escreve specs que são legíveis por humanos, mas ambíguas para agentes:
-
Requisitos densos em texto. As specs descrevem o que a funcionalidade deve fazer em forma de narrativa. Um leitor humano infere os detalhes não declarados a partir da experiência. Um agente não possui essa inferência — ou ele inventa os detalhes (alucinação) ou faz perguntas esclarecedoras (atrasos).
-
Critérios de aceitação não testáveis. Critérios como "o componente deve lidar com erros de forma graciosa" ou "a API deve ser performática" não podem ser validados por um Eval Harness. O agente não tem como verificar sua própria saída em relação a esses critérios, e o portão automatizado também não.
-
Condições de contorno ausentes. As specs descrevem o caminho feliz, mas omitem o tratamento de erros, estados vazios, acesso concorrente, casos de borda com caracteres especiais e valores de limite. Os agentes ignoram esses casos ou inventam um tratamento que não corresponde às expectativas da equipe.
-
Conhecimento arquitetural implícito. A spec diz "criar um novo serviço", mas não especifica qual padrão de camada de serviço seguir, em qual diretório colocar os arquivos, quais convenções de nomenclatura usar ou quais dependências são permitidas. O agente faz escolhas que podem violar regras arquiteturais não capturadas na spec.
-
Sem loop de feedback. As equipes não medem a qualidade das specs de forma sistemática. Uma spec que causou três rescue missions parece idêntica no backlog a uma spec que o agente acertou na primeira tentativa. Sem os dados de Spec To Code Ratio e Correction Ratio vinculados a specs individuais, não há sinal para melhoria.
Solução
Aplique uma metodologia de engenharia de specs de seis etapas que produz especificações legíveis por máquina, testáveis e independentes.
As Seis Etapas
- Comece com os critérios de aceitação — Escreva condições executáveis e testáveis antes de qualquer outra coisa.
- Escreva o contrato comportamental — Defina entradas, saídas, casos de borda e tratamento de erros.
- Defina a referência da constituição do sistema — Crie links para padrões de codificação, restrições arquiteturais e regras de segurança.
- Decomponha em um mapa de tarefas acionáveis — Divida a spec em subtarefas ordenadas que o agente possa executar sequencialmente.
- Anexe Golden Samples e referências de contexto — Forneça exemplos concretos da qualidade de saída esperada.
- Revise e valide antes da execução do agente — Trate as specs como código: revise-as, versione-as e teste-as.
Implementação
Exemplos de Código
// scripts/score-spec.ts
interface SpecQualityScore {
acceptanceCriteriaScore: number; // 0-25
behavioralContractScore: number; // 0-25
contextCompletenessScore: number; // 0-25
taskDecompositionScore: number; // 0-25
total: number; // 0-100
grade: "A" | "B" | "C" | "D" | "F";
suggestions: string[];
}
function scoreSpec(specContent: string): SpecQualityScore {
const suggestions: string[] = [];
// Score acceptance criteria
let acScore = 0;
const acTable = specContent.match(
/\| AC-\d+.*\|/g
);
if (acTable && acTable.length > 0) {
acScore += 10; // Has structured ACs
if (acTable.every((row) => row.includes("-test") || row.includes("-check"))) {
acScore += 10; // All ACs have validation methods
} else {
suggestions.push(
"Some acceptance criteria lack validation methods"
);
}
if (acTable.length >= 5) {
acScore += 5; // Sufficient coverage
} else {
suggestions.push(
"Consider adding more acceptance criteria for edge cases"
);
}
} else {
suggestions.push(
"Add structured acceptance criteria with IDs and validation methods"
);
}
// Score behavioral contract
let bcScore = 0;
if (specContent.includes("**Inputs:**")) bcScore += 5;
else suggestions.push("Add an Inputs table to the behavioral contract");
if (specContent.includes("**Outputs (success):**")) bcScore += 5;
else suggestions.push("Add a success Outputs table");
if (specContent.includes("**Outputs (error):**")) bcScore += 5;
else suggestions.push("Add an error Outputs table");
if (specContent.includes("**Behavior — Normal Flow:**")) bcScore += 5;
else suggestions.push("Add normal flow behavior description");
if (specContent.includes("**Behavior — Error Flow:**")) bcScore += 5;
else suggestions.push("Add error flow behavior description");
// Score context completeness
let ctxScore = 0;
if (specContent.includes("## System Constitution")) ctxScore += 5;
else suggestions.push("Add System Constitution reference");
if (specContent.includes("Golden Sample")) ctxScore += 10;
else suggestions.push("Add golden sample references");
if (specContent.includes("Context Packet")) ctxScore += 5;
else suggestions.push("Add context packet file listing");
if (specContent.includes("token") || specContent.includes("budget"))
ctxScore += 5;
else suggestions.push("Add token budget estimate");
// Score task decomposition
let tdScore = 0;
const taskMatches = specContent.match(/### Task \d+/g);
if (taskMatches && taskMatches.length > 0) {
tdScore += 10;
if (specContent.includes("**Dependencies:**")) tdScore += 5;
if (specContent.includes("**Validates:**")) tdScore += 5;
if (specContent.includes("**Golden Sample:**")) tdScore += 5;
} else {
suggestions.push("Decompose spec into ordered subtasks with dependencies");
}
const total = acScore + bcScore + ctxScore + tdScore;
const grade =
total >= 85
? "A"
: total >= 70
? "B"
: total >= 55
? "C"
: total >= 40
? "D"
: "F";
return {
acceptanceCriteriaScore: acScore,
behavioralContractScore: bcScore,
contextCompletenessScore: ctxScore,
taskDecompositionScore: tdScore,
total,
grade,
suggestions,
};
}# BEFORE: Vague spec that causes agent failures
# ------------------------------------------------
feature: User Authentication
description: Add login functionality
requirements:
- Users can log in with email and password
- Show error on invalid credentials
- Use JWT for sessions
notes: Follow existing patterns
# AFTER: Engineered spec that agents execute reliably
# ------------------------------------------------
feature: User Authentication — Login Endpoint
spec_version: 1
status: ready
author: "@context-architect"
behavioral_contract:
purpose: "Authenticate user by email/password, return signed JWT"
inputs:
- name: email
type: string
constraints: "RFC 5322 email format"
required: true
- name: password
type: string
constraints: "8-128 characters"
required: true
outputs_success:
- name: token
type: string
description: "RS256-signed JWT, 24h expiry, contains userId/email/role"
- name: user
type: object
description: "{ id: string, email: string, role: string }"
outputs_error:
- status: 401
code: AUTH_INVALID_CREDENTIALS
when: "Email exists but password does not match"
- status: 401
code: AUTH_USER_NOT_FOUND
when: "No user with provided email"
- status: 429
code: AUTH_RATE_LIMITED
when: "5+ failures from same IP in 15 minutes"
- status: 400
code: AUTH_INVALID_INPUT
when: "Email or password fails format validation"
acceptance_criteria:
- id: AC-1
criterion: "Returns 200 with JWT on valid credentials"
validation: integration-test
priority: must-have
- id: AC-2
criterion: "Returns 401 AUTH_INVALID_CREDENTIALS on wrong password"
validation: integration-test
priority: must-have
- id: AC-3
criterion: "Returns 429 after 5 failed attempts from same IP in 15min"
validation: integration-test
priority: must-have
- id: AC-4
criterion: "JWT uses RS256, contains userId/email/role, 24h expiry"
validation: unit-test
priority: must-have
- id: AC-5
criterion: "bcrypt timing-safe comparison for passwords"
validation: unit-test
priority: must-have
system_constitution_ref: "context/constitution/coding-standards.md"
golden_samples:
- path: "src/users/services/user-service.ts"
demonstrates: "Service pattern, error handling"
- path: "src/users/__tests__/user-service.test.ts"
demonstrates: "Test structure, mocking"
context_packet:
- "prisma/schema.prisma"
- "src/shared/errors/app-error.ts"
- "docs/api/auth-spec.yaml"
task_map:
- id: 1
name: "Input validation schema"
deliverable: "src/auth/schemas/login-schema.ts"
validates: [AC-4]
dependencies: []
- id: 2
name: "Auth service login method"
deliverable: "src/auth/services/auth-service.ts"
validates: [AC-1, AC-2, AC-3, AC-4, AC-5]
dependencies: [1]
- id: 3
name: "Auth controller login endpoint"
deliverable: "src/auth/controllers/auth-controller.ts"
validates: [AC-1, AC-2, AC-3]
dependencies: [2]
- id: 4
name: "Rate limiting middleware"
deliverable: "src/auth/middleware/rate-limiter.ts"
validates: [AC-3]
dependencies: []
- id: 5
name: "Tests for all acceptance criteria"
deliverable: "src/auth/__tests__/"
validates: [AC-1, AC-2, AC-3, AC-4, AC-5]
dependencies: [1, 2, 3, 4]
token_budget: 12000Considerações
- • **Higher Spec-to-Code Ratio.** Engineered specs leave less room for agent improvisation. When the spec defines inputs, outputs, error cases, and task decomposition, the agent follows the specification rather than guessing. Teams that adopt this methodology typically see [[spec-to-code-ratio]] increase from 50-60% to 80-90%.
- • **Fewer rescue missions.** The most common [[rescue-mission]] root cause is "ambiguous spec" (~40% of rescues). Engineered specs with testable acceptance criteria and explicit boundary conditions eliminate most of these. The [[correction-ratio]] drops because the agent gets it right on the first attempt.
- • **Specs become institutional knowledge.** A well-engineered spec is not a throwaway document — it is a reusable reference. When a similar feature needs to be built in the future, the team can adapt an existing spec rather than starting from scratch. The spec library grows into a valuable asset.
- • **Measurable quality improvement.** By tying [[spec-to-code-ratio]] and [[correction-ratio]] back to individual specs, teams can identify which spec patterns work and which do not. This creates a data-driven feedback loop for continuous improvement.
- • **Reduced onboarding time for new engineers.** A library of well-engineered specs teaches new team members how the codebase works, what patterns to follow, and what quality looks like. The specs are living documentation of the team's engineering standards.
- • **Initial slowdown perception.** Engineers accustomed to jumping straight into code perceive spec writing as overhead. The response is data: show that a 30-minute spec investment saves 2-3 hours of agent retries and human correction. Track the numbers to make the case.
- • **Spec maintenance as code evolves.** Specs that reference specific file paths, database schemas, or API contracts become stale as the codebase changes. Include spec staleness checks in the monthly Context Hygiene ceremony. Flag specs where referenced files have changed since the spec was last updated.
- • **Translation gap between business and technical language.** Product managers write requirements in business language. [[context-architect]] roles translate these into technical specs. The translation step introduces potential information loss. Pair the [[context-architect]] with the product manager during spec authoring to minimize gaps.
- • **Over-engineering specs for simple tasks.** Not every task needs a full six-step spec. A simple CRUD endpoint following an existing pattern may need only acceptance criteria and a golden sample reference. Scale the spec effort to the task complexity — use the routing matrix from [[agent-task-routing]] to determine how thorough the spec needs to be.
- • **Resistance to peer review of specs.** Engineers may view spec review as bureaucratic overhead. Frame it as the highest-leverage review activity: 15 minutes of spec review prevents hours of wasted agent execution. Start with lightweight reviews (a quick read-through) and formalize only for high-complexity tasks.